4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3180 Roo.bootstrap.NavGroup.register(this);
3184 * Fires when the active item changes
3185 * @param {Roo.bootstrap.NavGroup} this
3186 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3187 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3194 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3205 getAutoCreate : function()
3207 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3214 if (['tabs','pills'].indexOf(this.type)!==-1) {
3215 cfg.cls += ' nav-' + this.type
3217 if (this.type!=='nav') {
3218 Roo.log('nav type must be nav/tabs/pills')
3220 cfg.cls += ' navbar-nav'
3223 if (this.parent().sidebar) {
3226 cls: 'dashboard-menu sidebar-menu'
3232 if (this.form === true) {
3238 if (this.align === 'right') {
3239 cfg.cls += ' navbar-right';
3241 cfg.cls += ' navbar-left';
3245 if (this.align === 'right') {
3246 cfg.cls += ' navbar-right';
3250 cfg.cls += ' navbar-inverse';
3258 setActiveItem : function(item)
3261 Roo.each(this.navItems, function(v){
3266 v.setActive(false, true);
3273 item.setActive(true, true);
3274 this.fireEvent('changed', this, item, prev);
3279 addItem : function(cfg)
3281 var cn = new Roo.bootstrap.NavItem(cfg);
3283 cn.parentId = this.id;
3284 cn.onRender(this.el, null);
3288 register : function(item)
3290 this.navItems.push( item);
3291 item.navId = this.navId;
3294 getNavItem: function(tabId)
3297 Roo.each(this.navItems, function(e) {
3298 if (e.tabId == tabId) {
3314 Roo.apply(Roo.bootstrap.NavGroup, {
3318 register : function(navgrp)
3320 this.groups[navgrp.navId] = navgrp;
3323 get: function(navId) {
3324 return this.groups[navId];
3339 * @class Roo.bootstrap.NavItem
3340 * @extends Roo.bootstrap.Component
3341 * Bootstrap Navbar.NavItem class
3342 * @cfg {String} href link to
3343 * @cfg {String} html content of button
3344 * @cfg {String} badge text inside badge
3345 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3346 * @cfg {String} glyphicon name of glyphicon
3347 * @cfg {String} icon name of font awesome icon
3348 * @cfg {Boolean} active Is item active
3349 * @cfg {Boolean} disabled Is item disabled
3351 * @cfg {Boolean} preventDefault (true | false) default false
3352 * @cfg {String} tabId the tab that this item activates.
3353 * @cfg {String} tagtype (a|span) render as a href or span?
3356 * Create a new Navbar Item
3357 * @param {Object} config The config object
3359 Roo.bootstrap.NavItem = function(config){
3360 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3365 * The raw click event for the entire grid.
3366 * @param {Roo.EventObject} e
3371 * Fires when the active item active state changes
3372 * @param {Roo.bootstrap.NavItem} this
3373 * @param {boolean} state the new state
3381 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3389 preventDefault : false,
3394 getAutoCreate : function(){
3402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3404 if (this.disabled) {
3405 cfg.cls += ' disabled';
3408 if (this.href || this.html || this.glyphicon || this.icon) {
3412 href : this.href || "#",
3413 html: this.html || ''
3418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3421 if(this.glyphicon) {
3422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3427 cfg.cn[0].html += " <span class='caret'></span>";
3431 if (this.badge !== '') {
3433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3441 initEvents: function() {
3442 // Roo.log('init events?');
3443 // Roo.log(this.el.dom);
3444 if (typeof (this.menu) != 'undefined') {
3445 this.menu.parentType = this.xtype;
3446 this.menu.triggerEl = this.el;
3447 this.addxtype(Roo.apply({}, this.menu));
3451 this.el.select('a',true).on('click', this.onClick, this);
3452 // at this point parent should be available..
3453 this.parent().register(this);
3456 onClick : function(e)
3459 if(this.preventDefault){
3462 if (this.disabled) {
3465 Roo.log("fire event clicked");
3466 if(this.fireEvent('click', this, e) === false){
3470 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3471 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3472 this.parent().setActiveItem(this);
3480 isActive: function () {
3483 setActive : function(state, fire)
3485 this.active = state;
3487 this.el.removeClass('active');
3488 } else if (!this.el.hasClass('active')) {
3489 this.el.addClass('active');
3492 this.fireEvent('changed', this, state);
3497 // this should not be here...
3498 setDisabled : function(state)
3500 this.disabled = state;
3502 this.el.removeClass('disabled');
3503 } else if (!this.el.hasClass('disabled')) {
3504 this.el.addClass('disabled');
3517 * <span> icon </span>
3518 * <span> text </span>
3519 * <span>badge </span>
3523 * @class Roo.bootstrap.NavSidebarItem
3524 * @extends Roo.bootstrap.NavItem
3525 * Bootstrap Navbar.NavSidebarItem class
3527 * Create a new Navbar Button
3528 * @param {Object} config The config object
3530 Roo.bootstrap.NavSidebarItem = function(config){
3531 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3536 * The raw click event for the entire grid.
3537 * @param {Roo.EventObject} e
3542 * Fires when the active item active state changes
3543 * @param {Roo.bootstrap.NavSidebarItem} this
3544 * @param {boolean} state the new state
3552 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3555 getAutoCreate : function(){
3560 href : this.href || '#',
3572 html : this.html || ''
3577 cfg.cls += ' active';
3581 if (this.glyphicon || this.icon) {
3582 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3583 a.cn.push({ tag : 'i', cls : c }) ;
3588 if (this.badge !== '') {
3589 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3593 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3594 a.cls += 'dropdown-toggle treeview' ;
3618 * @class Roo.bootstrap.Row
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Row class (contains columns...)
3624 * @param {Object} config The config object
3627 Roo.bootstrap.Row = function(config){
3628 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3631 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3652 * @class Roo.bootstrap.Element
3653 * @extends Roo.bootstrap.Component
3654 * Bootstrap Element class
3655 * @cfg {String} html contents of the element
3656 * @cfg {String} tag tag of the element
3657 * @cfg {String} cls class of the element
3660 * Create a new Element
3661 * @param {Object} config The config object
3664 Roo.bootstrap.Element = function(config){
3665 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3675 getAutoCreate : function(){
3700 * @class Roo.bootstrap.Pagination
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap Pagination class
3703 * @cfg {String} size xs | sm | md | lg
3704 * @cfg {Boolean} inverse false | true
3707 * Create a new Pagination
3708 * @param {Object} config The config object
3711 Roo.bootstrap.Pagination = function(config){
3712 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3715 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3721 getAutoCreate : function(){
3727 cfg.cls += ' inverse';
3733 cfg.cls += " " + this.cls;
3751 * @class Roo.bootstrap.PaginationItem
3752 * @extends Roo.bootstrap.Component
3753 * Bootstrap PaginationItem class
3754 * @cfg {String} html text
3755 * @cfg {String} href the link
3756 * @cfg {Boolean} preventDefault (true | false) default true
3757 * @cfg {Boolean} active (true | false) default false
3761 * Create a new PaginationItem
3762 * @param {Object} config The config object
3766 Roo.bootstrap.PaginationItem = function(config){
3767 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3772 * The raw click event for the entire grid.
3773 * @param {Roo.EventObject} e
3779 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3783 preventDefault: true,
3787 getAutoCreate : function(){
3793 href : this.href ? this.href : '#',
3794 html : this.html ? this.html : ''
3804 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3810 initEvents: function() {
3812 this.el.on('click', this.onClick, this);
3815 onClick : function(e)
3817 Roo.log('PaginationItem on click ');
3818 if(this.preventDefault){
3822 this.fireEvent('click', this, e);
3838 * @class Roo.bootstrap.Slider
3839 * @extends Roo.bootstrap.Component
3840 * Bootstrap Slider class
3843 * Create a new Slider
3844 * @param {Object} config The config object
3847 Roo.bootstrap.Slider = function(config){
3848 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3851 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3853 getAutoCreate : function(){
3857 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3861 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.grid.ColumnModel
3885 * @extends Roo.util.Observable
3886 * This is the default implementation of a ColumnModel used by the Grid. It defines
3887 * the columns in the grid.
3890 var colModel = new Roo.grid.ColumnModel([
3891 {header: "Ticker", width: 60, sortable: true, locked: true},
3892 {header: "Company Name", width: 150, sortable: true},
3893 {header: "Market Cap.", width: 100, sortable: true},
3894 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3895 {header: "Employees", width: 100, sortable: true, resizable: false}
3900 * The config options listed for this class are options which may appear in each
3901 * individual column definition.
3902 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3904 * @param {Object} config An Array of column config objects. See this class's
3905 * config objects for details.
3907 Roo.grid.ColumnModel = function(config){
3909 * The config passed into the constructor
3911 this.config = config;
3914 // if no id, create one
3915 // if the column does not have a dataIndex mapping,
3916 // map it to the order it is in the config
3917 for(var i = 0, len = config.length; i < len; i++){
3919 if(typeof c.dataIndex == "undefined"){
3922 if(typeof c.renderer == "string"){
3923 c.renderer = Roo.util.Format[c.renderer];
3925 if(typeof c.id == "undefined"){
3928 if(c.editor && c.editor.xtype){
3929 c.editor = Roo.factory(c.editor, Roo.grid);
3931 if(c.editor && c.editor.isFormField){
3932 c.editor = new Roo.grid.GridEditor(c.editor);
3934 this.lookup[c.id] = c;
3938 * The width of columns which have no width specified (defaults to 100)
3941 this.defaultWidth = 100;
3944 * Default sortable of columns which have no sortable specified (defaults to false)
3947 this.defaultSortable = false;
3951 * @event widthchange
3952 * Fires when the width of a column changes.
3953 * @param {ColumnModel} this
3954 * @param {Number} columnIndex The column index
3955 * @param {Number} newWidth The new width
3957 "widthchange": true,
3959 * @event headerchange
3960 * Fires when the text of a header changes.
3961 * @param {ColumnModel} this
3962 * @param {Number} columnIndex The column index
3963 * @param {Number} newText The new header text
3965 "headerchange": true,
3967 * @event hiddenchange
3968 * Fires when a column is hidden or "unhidden".
3969 * @param {ColumnModel} this
3970 * @param {Number} columnIndex The column index
3971 * @param {Boolean} hidden true if hidden, false otherwise
3973 "hiddenchange": true,
3975 * @event columnmoved
3976 * Fires when a column is moved.
3977 * @param {ColumnModel} this
3978 * @param {Number} oldIndex
3979 * @param {Number} newIndex
3981 "columnmoved" : true,
3983 * @event columlockchange
3984 * Fires when a column's locked state is changed
3985 * @param {ColumnModel} this
3986 * @param {Number} colIndex
3987 * @param {Boolean} locked true if locked
3989 "columnlockchange" : true
3991 Roo.grid.ColumnModel.superclass.constructor.call(this);
3993 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3995 * @cfg {String} header The header text to display in the Grid view.
3998 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3999 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4000 * specified, the column's index is used as an index into the Record's data Array.
4003 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4004 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4007 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4008 * Defaults to the value of the {@link #defaultSortable} property.
4009 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4012 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4015 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4018 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4021 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4024 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4025 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4026 * default renderer uses the raw data value.
4029 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4032 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4036 * Returns the id of the column at the specified index.
4037 * @param {Number} index The column index
4038 * @return {String} the id
4040 getColumnId : function(index){
4041 return this.config[index].id;
4045 * Returns the column for a specified id.
4046 * @param {String} id The column id
4047 * @return {Object} the column
4049 getColumnById : function(id){
4050 return this.lookup[id];
4055 * Returns the column for a specified dataIndex.
4056 * @param {String} dataIndex The column dataIndex
4057 * @return {Object|Boolean} the column or false if not found
4059 getColumnByDataIndex: function(dataIndex){
4060 var index = this.findColumnIndex(dataIndex);
4061 return index > -1 ? this.config[index] : false;
4065 * Returns the index for a specified column id.
4066 * @param {String} id The column id
4067 * @return {Number} the index, or -1 if not found
4069 getIndexById : function(id){
4070 for(var i = 0, len = this.config.length; i < len; i++){
4071 if(this.config[i].id == id){
4079 * Returns the index for a specified column dataIndex.
4080 * @param {String} dataIndex The column dataIndex
4081 * @return {Number} the index, or -1 if not found
4084 findColumnIndex : function(dataIndex){
4085 for(var i = 0, len = this.config.length; i < len; i++){
4086 if(this.config[i].dataIndex == dataIndex){
4094 moveColumn : function(oldIndex, newIndex){
4095 var c = this.config[oldIndex];
4096 this.config.splice(oldIndex, 1);
4097 this.config.splice(newIndex, 0, c);
4098 this.dataMap = null;
4099 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4102 isLocked : function(colIndex){
4103 return this.config[colIndex].locked === true;
4106 setLocked : function(colIndex, value, suppressEvent){
4107 if(this.isLocked(colIndex) == value){
4110 this.config[colIndex].locked = value;
4112 this.fireEvent("columnlockchange", this, colIndex, value);
4116 getTotalLockedWidth : function(){
4118 for(var i = 0; i < this.config.length; i++){
4119 if(this.isLocked(i) && !this.isHidden(i)){
4120 this.totalWidth += this.getColumnWidth(i);
4126 getLockedCount : function(){
4127 for(var i = 0, len = this.config.length; i < len; i++){
4128 if(!this.isLocked(i)){
4135 * Returns the number of columns.
4138 getColumnCount : function(visibleOnly){
4139 if(visibleOnly === true){
4141 for(var i = 0, len = this.config.length; i < len; i++){
4142 if(!this.isHidden(i)){
4148 return this.config.length;
4152 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4153 * @param {Function} fn
4154 * @param {Object} scope (optional)
4155 * @return {Array} result
4157 getColumnsBy : function(fn, scope){
4159 for(var i = 0, len = this.config.length; i < len; i++){
4160 var c = this.config[i];
4161 if(fn.call(scope||this, c, i) === true){
4169 * Returns true if the specified column is sortable.
4170 * @param {Number} col The column index
4173 isSortable : function(col){
4174 if(typeof this.config[col].sortable == "undefined"){
4175 return this.defaultSortable;
4177 return this.config[col].sortable;
4181 * Returns the rendering (formatting) function defined for the column.
4182 * @param {Number} col The column index.
4183 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4185 getRenderer : function(col){
4186 if(!this.config[col].renderer){
4187 return Roo.grid.ColumnModel.defaultRenderer;
4189 return this.config[col].renderer;
4193 * Sets the rendering (formatting) function for a column.
4194 * @param {Number} col The column index
4195 * @param {Function} fn The function to use to process the cell's raw data
4196 * to return HTML markup for the grid view. The render function is called with
4197 * the following parameters:<ul>
4198 * <li>Data value.</li>
4199 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4200 * <li>css A CSS style string to apply to the table cell.</li>
4201 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4202 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4203 * <li>Row index</li>
4204 * <li>Column index</li>
4205 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4207 setRenderer : function(col, fn){
4208 this.config[col].renderer = fn;
4212 * Returns the width for the specified column.
4213 * @param {Number} col The column index
4216 getColumnWidth : function(col){
4217 return this.config[col].width * 1 || this.defaultWidth;
4221 * Sets the width for a column.
4222 * @param {Number} col The column index
4223 * @param {Number} width The new width
4225 setColumnWidth : function(col, width, suppressEvent){
4226 this.config[col].width = width;
4227 this.totalWidth = null;
4229 this.fireEvent("widthchange", this, col, width);
4234 * Returns the total width of all columns.
4235 * @param {Boolean} includeHidden True to include hidden column widths
4238 getTotalWidth : function(includeHidden){
4239 if(!this.totalWidth){
4240 this.totalWidth = 0;
4241 for(var i = 0, len = this.config.length; i < len; i++){
4242 if(includeHidden || !this.isHidden(i)){
4243 this.totalWidth += this.getColumnWidth(i);
4247 return this.totalWidth;
4251 * Returns the header for the specified column.
4252 * @param {Number} col The column index
4255 getColumnHeader : function(col){
4256 return this.config[col].header;
4260 * Sets the header for a column.
4261 * @param {Number} col The column index
4262 * @param {String} header The new header
4264 setColumnHeader : function(col, header){
4265 this.config[col].header = header;
4266 this.fireEvent("headerchange", this, col, header);
4270 * Returns the tooltip for the specified column.
4271 * @param {Number} col The column index
4274 getColumnTooltip : function(col){
4275 return this.config[col].tooltip;
4278 * Sets the tooltip for a column.
4279 * @param {Number} col The column index
4280 * @param {String} tooltip The new tooltip
4282 setColumnTooltip : function(col, tooltip){
4283 this.config[col].tooltip = tooltip;
4287 * Returns the dataIndex for the specified column.
4288 * @param {Number} col The column index
4291 getDataIndex : function(col){
4292 return this.config[col].dataIndex;
4296 * Sets the dataIndex for a column.
4297 * @param {Number} col The column index
4298 * @param {Number} dataIndex The new dataIndex
4300 setDataIndex : function(col, dataIndex){
4301 this.config[col].dataIndex = dataIndex;
4307 * Returns true if the cell is editable.
4308 * @param {Number} colIndex The column index
4309 * @param {Number} rowIndex The row index
4312 isCellEditable : function(colIndex, rowIndex){
4313 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4317 * Returns the editor defined for the cell/column.
4318 * return false or null to disable editing.
4319 * @param {Number} colIndex The column index
4320 * @param {Number} rowIndex The row index
4323 getCellEditor : function(colIndex, rowIndex){
4324 return this.config[colIndex].editor;
4328 * Sets if a column is editable.
4329 * @param {Number} col The column index
4330 * @param {Boolean} editable True if the column is editable
4332 setEditable : function(col, editable){
4333 this.config[col].editable = editable;
4338 * Returns true if the column is hidden.
4339 * @param {Number} colIndex The column index
4342 isHidden : function(colIndex){
4343 return this.config[colIndex].hidden;
4348 * Returns true if the column width cannot be changed
4350 isFixed : function(colIndex){
4351 return this.config[colIndex].fixed;
4355 * Returns true if the column can be resized
4358 isResizable : function(colIndex){
4359 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4362 * Sets if a column is hidden.
4363 * @param {Number} colIndex The column index
4364 * @param {Boolean} hidden True if the column is hidden
4366 setHidden : function(colIndex, hidden){
4367 this.config[colIndex].hidden = hidden;
4368 this.totalWidth = null;
4369 this.fireEvent("hiddenchange", this, colIndex, hidden);
4373 * Sets the editor for a column.
4374 * @param {Number} col The column index
4375 * @param {Object} editor The editor object
4377 setEditor : function(col, editor){
4378 this.config[col].editor = editor;
4382 Roo.grid.ColumnModel.defaultRenderer = function(value){
4383 if(typeof value == "string" && value.length < 1){
4389 // Alias for backwards compatibility
4390 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4393 * Ext JS Library 1.1.1
4394 * Copyright(c) 2006-2007, Ext JS, LLC.
4396 * Originally Released Under LGPL - original licence link has changed is not relivant.
4399 * <script type="text/javascript">
4403 * @class Roo.LoadMask
4404 * A simple utility class for generically masking elements while loading data. If the element being masked has
4405 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4406 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4407 * element's UpdateManager load indicator and will be destroyed after the initial load.
4409 * Create a new LoadMask
4410 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4411 * @param {Object} config The config object
4413 Roo.LoadMask = function(el, config){
4414 this.el = Roo.get(el);
4415 Roo.apply(this, config);
4417 this.store.on('beforeload', this.onBeforeLoad, this);
4418 this.store.on('load', this.onLoad, this);
4419 this.store.on('loadexception', this.onLoadException, this);
4420 this.removeMask = false;
4422 var um = this.el.getUpdateManager();
4423 um.showLoadIndicator = false; // disable the default indicator
4424 um.on('beforeupdate', this.onBeforeLoad, this);
4425 um.on('update', this.onLoad, this);
4426 um.on('failure', this.onLoad, this);
4427 this.removeMask = true;
4431 Roo.LoadMask.prototype = {
4433 * @cfg {Boolean} removeMask
4434 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4435 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4439 * The text to display in a centered loading message box (defaults to 'Loading...')
4443 * @cfg {String} msgCls
4444 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4446 msgCls : 'x-mask-loading',
4449 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4455 * Disables the mask to prevent it from being displayed
4457 disable : function(){
4458 this.disabled = true;
4462 * Enables the mask so that it can be displayed
4464 enable : function(){
4465 this.disabled = false;
4468 onLoadException : function()
4472 if (typeof(arguments[3]) != 'undefined') {
4473 Roo.MessageBox.alert("Error loading",arguments[3]);
4477 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4478 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4487 this.el.unmask(this.removeMask);
4492 this.el.unmask(this.removeMask);
4496 onBeforeLoad : function(){
4498 this.el.mask(this.msg, this.msgCls);
4503 destroy : function(){
4505 this.store.un('beforeload', this.onBeforeLoad, this);
4506 this.store.un('load', this.onLoad, this);
4507 this.store.un('loadexception', this.onLoadException, this);
4509 var um = this.el.getUpdateManager();
4510 um.un('beforeupdate', this.onBeforeLoad, this);
4511 um.un('update', this.onLoad, this);
4512 um.un('failure', this.onLoad, this);
4523 * @class Roo.bootstrap.Table
4524 * @extends Roo.bootstrap.Component
4525 * Bootstrap Table class
4526 * @cfg {String} cls table class
4527 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4528 * @cfg {String} bgcolor Specifies the background color for a table
4529 * @cfg {Number} border Specifies whether the table cells should have borders or not
4530 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4531 * @cfg {Number} cellspacing Specifies the space between cells
4532 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4533 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4534 * @cfg {String} sortable Specifies that the table should be sortable
4535 * @cfg {String} summary Specifies a summary of the content of a table
4536 * @cfg {Number} width Specifies the width of a table
4537 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4539 * @cfg {boolean} striped Should the rows be alternative striped
4540 * @cfg {boolean} bordered Add borders to the table
4541 * @cfg {boolean} hover Add hover highlighting
4542 * @cfg {boolean} condensed Format condensed
4543 * @cfg {boolean} responsive Format condensed
4544 * @cfg {Boolean} loadMask (true|false) default false
4545 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4546 * @cfg {Boolean} thead (true|false) generate thead, default true
4547 * @cfg {Boolean} RowSelection (true|false) default false
4548 * @cfg {Boolean} CellSelection (true|false) default false
4550 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4554 * Create a new Table
4555 * @param {Object} config The config object
4558 Roo.bootstrap.Table = function(config){
4559 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4562 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4563 this.sm = this.selModel;
4564 this.sm.xmodule = this.xmodule || false;
4566 if (this.cm && typeof(this.cm.config) == 'undefined') {
4567 this.colModel = new Roo.grid.ColumnModel(this.cm);
4568 this.cm = this.colModel;
4569 this.cm.xmodule = this.xmodule || false;
4572 this.store= Roo.factory(this.store, Roo.data);
4573 this.ds = this.store;
4574 this.ds.xmodule = this.xmodule || false;
4577 if (this.footer && this.store) {
4578 this.footer.dataSource = this.ds;
4579 this.footer = Roo.factory(this.footer);
4586 * Fires when a cell is clicked
4587 * @param {Roo.bootstrap.Table} this
4588 * @param {Roo.Element} el
4589 * @param {Number} rowIndex
4590 * @param {Number} columnIndex
4591 * @param {Roo.EventObject} e
4595 * @event celldblclick
4596 * Fires when a cell is double clicked
4597 * @param {Roo.bootstrap.Table} this
4598 * @param {Roo.Element} el
4599 * @param {Number} rowIndex
4600 * @param {Number} columnIndex
4601 * @param {Roo.EventObject} e
4603 "celldblclick" : true,
4606 * Fires when a row is clicked
4607 * @param {Roo.bootstrap.Table} this
4608 * @param {Roo.Element} el
4609 * @param {Number} rowIndex
4610 * @param {Roo.EventObject} e
4614 * @event rowdblclick
4615 * Fires when a row is double clicked
4616 * @param {Roo.bootstrap.Table} this
4617 * @param {Roo.Element} el
4618 * @param {Number} rowIndex
4619 * @param {Roo.EventObject} e
4621 "rowdblclick" : true,
4624 * Fires when a mouseover occur
4625 * @param {Roo.bootstrap.Table} this
4626 * @param {Roo.Element} el
4627 * @param {Number} rowIndex
4628 * @param {Number} columnIndex
4629 * @param {Roo.EventObject} e
4634 * Fires when a mouseout occur
4635 * @param {Roo.bootstrap.Table} this
4636 * @param {Roo.Element} el
4637 * @param {Number} rowIndex
4638 * @param {Number} columnIndex
4639 * @param {Roo.EventObject} e
4644 * Fires when a row is rendered, so you can change add a style to it.
4645 * @param {Roo.bootstrap.Table} this
4646 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4651 * Fires when record have been loaded
4652 * @param {Roo.bootstrap.Table} this
4653 * @param {Object} records store records
4660 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4684 RowSelection : false,
4685 CellSelection : false,
4689 getAutoCreate : function(){
4690 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4699 cfg.cls += ' table-striped';
4703 cfg.cls += ' table-hover';
4705 if (this.bordered) {
4706 cfg.cls += ' table-bordered';
4708 if (this.condensed) {
4709 cfg.cls += ' table-condensed';
4711 if (this.responsive) {
4712 cfg.cls += ' table-responsive';
4716 cfg.cls+= ' ' +this.cls;
4719 // this lot should be simplifed...
4722 cfg.align=this.align;
4725 cfg.bgcolor=this.bgcolor;
4728 cfg.border=this.border;
4730 if (this.cellpadding) {
4731 cfg.cellpadding=this.cellpadding;
4733 if (this.cellspacing) {
4734 cfg.cellspacing=this.cellspacing;
4737 cfg.frame=this.frame;
4740 cfg.rules=this.rules;
4742 if (this.sortable) {
4743 cfg.sortable=this.sortable;
4746 cfg.summary=this.summary;
4749 cfg.width=this.width;
4752 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4755 if(this.store || this.cm){
4757 cfg.cn.push(this.renderHeader());
4760 cfg.cn.push(this.renderBody());
4763 cfg.cn.push(this.renderFooter());
4766 cfg.cls+= ' TableGrid';
4769 return { cn : [ cfg ] };
4772 initEvents : function()
4774 if(!this.store || !this.cm){
4778 Roo.log('initEvents with ds!!!!');
4782 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4783 e.on('click', _this.sort, _this);
4786 this.el.on("click", this.onClick, this);
4787 this.el.on("dblclick", this.onDblClick, this);
4789 this.parent().el.setStyle('position', 'relative');
4791 this.footer.parentId = this.id;
4792 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4795 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4797 this.store.on('load', this.onLoad, this);
4798 this.store.on('beforeload', this.onBeforeLoad, this);
4802 onMouseover : function(e, el)
4804 var cell = Roo.get(el);
4810 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4811 cell = cell.findParent('td', false, true);
4814 var row = cell.findParent('tr', false, true);
4815 var cellIndex = cell.dom.cellIndex;
4816 var rowIndex = row.dom.rowIndex - 1; // start from 0
4818 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4822 onMouseout : function(e, el)
4824 var cell = Roo.get(el);
4830 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4831 cell = cell.findParent('td', false, true);
4834 var row = cell.findParent('tr', false, true);
4835 var cellIndex = cell.dom.cellIndex;
4836 var rowIndex = row.dom.rowIndex - 1; // start from 0
4838 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4842 onClick : function(e, el)
4844 var cell = Roo.get(el);
4846 if(!cell || !this.CellSelection || !this.RowSelection){
4851 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4852 cell = cell.findParent('td', false, true);
4855 var row = cell.findParent('tr', false, true);
4856 var cellIndex = cell.dom.cellIndex;
4857 var rowIndex = row.dom.rowIndex - 1;
4859 if(this.CellSelection){
4860 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4863 if(this.RowSelection){
4864 this.fireEvent('rowclick', this, row, rowIndex, e);
4870 onDblClick : function(e,el)
4872 var cell = Roo.get(el);
4874 if(!cell || !this.CellSelection || !this.RowSelection){
4878 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4879 cell = cell.findParent('td', false, true);
4882 var row = cell.findParent('tr', false, true);
4883 var cellIndex = cell.dom.cellIndex;
4884 var rowIndex = row.dom.rowIndex - 1;
4886 if(this.CellSelection){
4887 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4890 if(this.RowSelection){
4891 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4895 sort : function(e,el)
4897 var col = Roo.get(el)
4899 if(!col.hasClass('sortable')){
4903 var sort = col.attr('sort');
4906 if(col.hasClass('glyphicon-arrow-up')){
4910 this.store.sortInfo = {field : sort, direction : dir};
4913 Roo.log("calling footer first");
4914 this.footer.onClick('first');
4917 this.store.load({ params : { start : 0 } });
4921 renderHeader : function()
4930 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4932 var config = cm.config[i];
4937 html: cm.getColumnHeader(i)
4940 if(typeof(config.hidden) != 'undefined' && config.hidden){
4941 c.style += ' display:none;';
4944 if(typeof(config.dataIndex) != 'undefined'){
4945 c.sort = config.dataIndex;
4948 if(typeof(config.sortable) != 'undefined' && config.sortable){
4952 // if(typeof(config.align) != 'undefined' && config.align.length){
4953 // c.style += ' text-align:' + config.align + ';';
4956 if(typeof(config.width) != 'undefined'){
4957 c.style += ' width:' + config.width + 'px;';
4966 renderBody : function()
4976 colspan : this.cm.getColumnCount()
4986 renderFooter : function()
4996 colspan : this.cm.getColumnCount()
5008 Roo.log('ds onload');
5014 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5015 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5017 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5018 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5021 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5022 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5026 var tbody = this.el.select('tbody', true).first();
5030 if(this.store.getCount() > 0){
5031 this.store.data.each(function(d,rowIndex){
5037 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5038 var config = cm.config[i];
5040 var renderer = cm.getRenderer(i);
5044 if(typeof(renderer) !== 'undefined'){
5045 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5048 if(typeof(value) === 'object'){
5057 rowIndex : rowIndex,
5062 _this.fireEvent('rowclass', this, rowcfg);
5067 cls : rowcfg.rowClass,
5069 html: (typeof(value) === 'object') ? '' : value
5072 if(typeof(config.hidden) != 'undefined' && config.hidden){
5073 td.style += ' display:none;';
5076 if(typeof(config.align) != 'undefined' && config.align.length){
5077 td.style += ' text-align:' + config.align + ';';
5080 if(typeof(config.width) != 'undefined'){
5081 td.style += ' width:' + config.width + 'px;';
5089 tbody.createChild(row);
5097 Roo.each(renders, function(r){
5098 _this.renderColumn(r);
5102 Roo.each(this.el.select('tbody td', true).elements, function(e){
5103 e.on('mouseover', _this.onMouseover, _this);
5106 Roo.each(this.el.select('tbody td', true).elements, function(e){
5107 e.on('mouseout', _this.onMouseout, _this);
5110 this.fireEvent('afterload', this, this.store.data);
5111 //if(this.loadMask){
5112 // this.maskEl.hide();
5116 onBeforeLoad : function()
5118 //Roo.log('ds onBeforeLoad');
5122 //if(this.loadMask){
5123 // this.maskEl.show();
5129 this.el.select('tbody', true).first().dom.innerHTML = '';
5132 getSelectionModel : function(){
5134 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5136 return this.selModel;
5139 renderColumn : function(r)
5143 var t = r.cfg.render(r.container);
5146 Roo.each(r.cfg.cn, function(c){
5148 container: t.getChildContainer(),
5151 _this.renderColumn(child);
5168 * @class Roo.bootstrap.TableCell
5169 * @extends Roo.bootstrap.Component
5170 * Bootstrap TableCell class
5171 * @cfg {String} html cell contain text
5172 * @cfg {String} cls cell class
5173 * @cfg {String} tag cell tag (td|th) default td
5174 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5175 * @cfg {String} align Aligns the content in a cell
5176 * @cfg {String} axis Categorizes cells
5177 * @cfg {String} bgcolor Specifies the background color of a cell
5178 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5179 * @cfg {Number} colspan Specifies the number of columns a cell should span
5180 * @cfg {String} headers Specifies one or more header cells a cell is related to
5181 * @cfg {Number} height Sets the height of a cell
5182 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5183 * @cfg {Number} rowspan Sets the number of rows a cell should span
5184 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5185 * @cfg {String} valign Vertical aligns the content in a cell
5186 * @cfg {Number} width Specifies the width of a cell
5189 * Create a new TableCell
5190 * @param {Object} config The config object
5193 Roo.bootstrap.TableCell = function(config){
5194 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5197 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5217 getAutoCreate : function(){
5218 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5238 cfg.align=this.align
5244 cfg.bgcolor=this.bgcolor
5247 cfg.charoff=this.charoff
5250 cfg.colspan=this.colspan
5253 cfg.headers=this.headers
5256 cfg.height=this.height
5259 cfg.nowrap=this.nowrap
5262 cfg.rowspan=this.rowspan
5265 cfg.scope=this.scope
5268 cfg.valign=this.valign
5271 cfg.width=this.width
5290 * @class Roo.bootstrap.TableRow
5291 * @extends Roo.bootstrap.Component
5292 * Bootstrap TableRow class
5293 * @cfg {String} cls row class
5294 * @cfg {String} align Aligns the content in a table row
5295 * @cfg {String} bgcolor Specifies a background color for a table row
5296 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5297 * @cfg {String} valign Vertical aligns the content in a table row
5300 * Create a new TableRow
5301 * @param {Object} config The config object
5304 Roo.bootstrap.TableRow = function(config){
5305 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5308 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5316 getAutoCreate : function(){
5317 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5327 cfg.align = this.align;
5330 cfg.bgcolor = this.bgcolor;
5333 cfg.charoff = this.charoff;
5336 cfg.valign = this.valign;
5354 * @class Roo.bootstrap.TableBody
5355 * @extends Roo.bootstrap.Component
5356 * Bootstrap TableBody class
5357 * @cfg {String} cls element class
5358 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5359 * @cfg {String} align Aligns the content inside the element
5360 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5361 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5364 * Create a new TableBody
5365 * @param {Object} config The config object
5368 Roo.bootstrap.TableBody = function(config){
5369 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5372 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5380 getAutoCreate : function(){
5381 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5395 cfg.align = this.align;
5398 cfg.charoff = this.charoff;
5401 cfg.valign = this.valign;
5408 // initEvents : function()
5415 // this.store = Roo.factory(this.store, Roo.data);
5416 // this.store.on('load', this.onLoad, this);
5418 // this.store.load();
5422 // onLoad: function ()
5424 // this.fireEvent('load', this);
5434 * Ext JS Library 1.1.1
5435 * Copyright(c) 2006-2007, Ext JS, LLC.
5437 * Originally Released Under LGPL - original licence link has changed is not relivant.
5440 * <script type="text/javascript">
5443 // as we use this in bootstrap.
5444 Roo.namespace('Roo.form');
5446 * @class Roo.form.Action
5447 * Internal Class used to handle form actions
5449 * @param {Roo.form.BasicForm} el The form element or its id
5450 * @param {Object} config Configuration options
5455 // define the action interface
5456 Roo.form.Action = function(form, options){
5458 this.options = options || {};
5461 * Client Validation Failed
5464 Roo.form.Action.CLIENT_INVALID = 'client';
5466 * Server Validation Failed
5469 Roo.form.Action.SERVER_INVALID = 'server';
5471 * Connect to Server Failed
5474 Roo.form.Action.CONNECT_FAILURE = 'connect';
5476 * Reading Data from Server Failed
5479 Roo.form.Action.LOAD_FAILURE = 'load';
5481 Roo.form.Action.prototype = {
5483 failureType : undefined,
5484 response : undefined,
5488 run : function(options){
5493 success : function(response){
5498 handleResponse : function(response){
5502 // default connection failure
5503 failure : function(response){
5505 this.response = response;
5506 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5507 this.form.afterAction(this, false);
5510 processResponse : function(response){
5511 this.response = response;
5512 if(!response.responseText){
5515 this.result = this.handleResponse(response);
5519 // utility functions used internally
5520 getUrl : function(appendParams){
5521 var url = this.options.url || this.form.url || this.form.el.dom.action;
5523 var p = this.getParams();
5525 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5531 getMethod : function(){
5532 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5535 getParams : function(){
5536 var bp = this.form.baseParams;
5537 var p = this.options.params;
5539 if(typeof p == "object"){
5540 p = Roo.urlEncode(Roo.applyIf(p, bp));
5541 }else if(typeof p == 'string' && bp){
5542 p += '&' + Roo.urlEncode(bp);
5545 p = Roo.urlEncode(bp);
5550 createCallback : function(){
5552 success: this.success,
5553 failure: this.failure,
5555 timeout: (this.form.timeout*1000),
5556 upload: this.form.fileUpload ? this.success : undefined
5561 Roo.form.Action.Submit = function(form, options){
5562 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5565 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5568 haveProgress : false,
5569 uploadComplete : false,
5571 // uploadProgress indicator.
5572 uploadProgress : function()
5574 if (!this.form.progressUrl) {
5578 if (!this.haveProgress) {
5579 Roo.MessageBox.progress("Uploading", "Uploading");
5581 if (this.uploadComplete) {
5582 Roo.MessageBox.hide();
5586 this.haveProgress = true;
5588 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5590 var c = new Roo.data.Connection();
5592 url : this.form.progressUrl,
5597 success : function(req){
5598 //console.log(data);
5602 rdata = Roo.decode(req.responseText)
5604 Roo.log("Invalid data from server..");
5608 if (!rdata || !rdata.success) {
5610 Roo.MessageBox.alert(Roo.encode(rdata));
5613 var data = rdata.data;
5615 if (this.uploadComplete) {
5616 Roo.MessageBox.hide();
5621 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5622 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5625 this.uploadProgress.defer(2000,this);
5628 failure: function(data) {
5629 Roo.log('progress url failed ');
5640 // run get Values on the form, so it syncs any secondary forms.
5641 this.form.getValues();
5643 var o = this.options;
5644 var method = this.getMethod();
5645 var isPost = method == 'POST';
5646 if(o.clientValidation === false || this.form.isValid()){
5648 if (this.form.progressUrl) {
5649 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5650 (new Date() * 1) + '' + Math.random());
5655 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5656 form:this.form.el.dom,
5657 url:this.getUrl(!isPost),
5659 params:isPost ? this.getParams() : null,
5660 isUpload: this.form.fileUpload
5663 this.uploadProgress();
5665 }else if (o.clientValidation !== false){ // client validation failed
5666 this.failureType = Roo.form.Action.CLIENT_INVALID;
5667 this.form.afterAction(this, false);
5671 success : function(response)
5673 this.uploadComplete= true;
5674 if (this.haveProgress) {
5675 Roo.MessageBox.hide();
5679 var result = this.processResponse(response);
5680 if(result === true || result.success){
5681 this.form.afterAction(this, true);
5685 this.form.markInvalid(result.errors);
5686 this.failureType = Roo.form.Action.SERVER_INVALID;
5688 this.form.afterAction(this, false);
5690 failure : function(response)
5692 this.uploadComplete= true;
5693 if (this.haveProgress) {
5694 Roo.MessageBox.hide();
5697 this.response = response;
5698 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5699 this.form.afterAction(this, false);
5702 handleResponse : function(response){
5703 if(this.form.errorReader){
5704 var rs = this.form.errorReader.read(response);
5707 for(var i = 0, len = rs.records.length; i < len; i++) {
5708 var r = rs.records[i];
5712 if(errors.length < 1){
5716 success : rs.success,
5722 ret = Roo.decode(response.responseText);
5726 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5736 Roo.form.Action.Load = function(form, options){
5737 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5738 this.reader = this.form.reader;
5741 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5746 Roo.Ajax.request(Roo.apply(
5747 this.createCallback(), {
5748 method:this.getMethod(),
5749 url:this.getUrl(false),
5750 params:this.getParams()
5754 success : function(response){
5756 var result = this.processResponse(response);
5757 if(result === true || !result.success || !result.data){
5758 this.failureType = Roo.form.Action.LOAD_FAILURE;
5759 this.form.afterAction(this, false);
5762 this.form.clearInvalid();
5763 this.form.setValues(result.data);
5764 this.form.afterAction(this, true);
5767 handleResponse : function(response){
5768 if(this.form.reader){
5769 var rs = this.form.reader.read(response);
5770 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5772 success : rs.success,
5776 return Roo.decode(response.responseText);
5780 Roo.form.Action.ACTION_TYPES = {
5781 'load' : Roo.form.Action.Load,
5782 'submit' : Roo.form.Action.Submit
5791 * @class Roo.bootstrap.Form
5792 * @extends Roo.bootstrap.Component
5793 * Bootstrap Form class
5794 * @cfg {String} method GET | POST (default POST)
5795 * @cfg {String} labelAlign top | left (default top)
5796 * @cfg {String} align left | right - for navbars
5801 * @param {Object} config The config object
5805 Roo.bootstrap.Form = function(config){
5806 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5809 * @event clientvalidation
5810 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5811 * @param {Form} this
5812 * @param {Boolean} valid true if the form has passed client-side validation
5814 clientvalidation: true,
5816 * @event beforeaction
5817 * Fires before any action is performed. Return false to cancel the action.
5818 * @param {Form} this
5819 * @param {Action} action The action to be performed
5823 * @event actionfailed
5824 * Fires when an action fails.
5825 * @param {Form} this
5826 * @param {Action} action The action that failed
5828 actionfailed : true,
5830 * @event actioncomplete
5831 * Fires when an action is completed.
5832 * @param {Form} this
5833 * @param {Action} action The action that completed
5835 actioncomplete : true
5840 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5843 * @cfg {String} method
5844 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5849 * The URL to use for form actions if one isn't supplied in the action options.
5852 * @cfg {Boolean} fileUpload
5853 * Set to true if this form is a file upload.
5857 * @cfg {Object} baseParams
5858 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5862 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5866 * @cfg {Sting} align (left|right) for navbar forms
5871 activeAction : null,
5874 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5875 * element by passing it or its id or mask the form itself by passing in true.
5878 waitMsgTarget : false,
5883 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5884 * element by passing it or its id or mask the form itself by passing in true.
5888 getAutoCreate : function(){
5892 method : this.method || 'POST',
5893 id : this.id || Roo.id(),
5896 if (this.parent().xtype.match(/^Nav/)) {
5897 cfg.cls = 'navbar-form navbar-' + this.align;
5901 if (this.labelAlign == 'left' ) {
5902 cfg.cls += ' form-horizontal';
5908 initEvents : function()
5910 this.el.on('submit', this.onSubmit, this);
5911 // this was added as random key presses on the form where triggering form submit.
5912 this.el.on('keypress', function(e) {
5913 if (e.getCharCode() != 13) {
5916 // we might need to allow it for textareas.. and some other items.
5917 // check e.getTarget().
5919 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
5923 Roo.log("keypress blocked");
5931 onSubmit : function(e){
5936 * Returns true if client-side validation on the form is successful.
5939 isValid : function(){
5940 var items = this.getItems();
5942 items.each(function(f){
5951 * Returns true if any fields in this form have changed since their original load.
5954 isDirty : function(){
5956 var items = this.getItems();
5957 items.each(function(f){
5967 * Performs a predefined action (submit or load) or custom actions you define on this form.
5968 * @param {String} actionName The name of the action type
5969 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5970 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5971 * accept other config options):
5973 Property Type Description
5974 ---------------- --------------- ----------------------------------------------------------------------------------
5975 url String The url for the action (defaults to the form's url)
5976 method String The form method to use (defaults to the form's method, or POST if not defined)
5977 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5978 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5979 validate the form on the client (defaults to false)
5981 * @return {BasicForm} this
5983 doAction : function(action, options){
5984 if(typeof action == 'string'){
5985 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5987 if(this.fireEvent('beforeaction', this, action) !== false){
5988 this.beforeAction(action);
5989 action.run.defer(100, action);
5995 beforeAction : function(action){
5996 var o = action.options;
5998 // not really supported yet.. ??
6000 //if(this.waitMsgTarget === true){
6001 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6002 //}else if(this.waitMsgTarget){
6003 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6004 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6006 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6012 afterAction : function(action, success){
6013 this.activeAction = null;
6014 var o = action.options;
6016 //if(this.waitMsgTarget === true){
6018 //}else if(this.waitMsgTarget){
6019 // this.waitMsgTarget.unmask();
6021 // Roo.MessageBox.updateProgress(1);
6022 // Roo.MessageBox.hide();
6029 Roo.callback(o.success, o.scope, [this, action]);
6030 this.fireEvent('actioncomplete', this, action);
6034 // failure condition..
6035 // we have a scenario where updates need confirming.
6036 // eg. if a locking scenario exists..
6037 // we look for { errors : { needs_confirm : true }} in the response.
6039 (typeof(action.result) != 'undefined') &&
6040 (typeof(action.result.errors) != 'undefined') &&
6041 (typeof(action.result.errors.needs_confirm) != 'undefined')
6044 Roo.log("not supported yet");
6047 Roo.MessageBox.confirm(
6048 "Change requires confirmation",
6049 action.result.errorMsg,
6054 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6064 Roo.callback(o.failure, o.scope, [this, action]);
6065 // show an error message if no failed handler is set..
6066 if (!this.hasListener('actionfailed')) {
6067 Roo.log("need to add dialog support");
6069 Roo.MessageBox.alert("Error",
6070 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6071 action.result.errorMsg :
6072 "Saving Failed, please check your entries or try again"
6077 this.fireEvent('actionfailed', this, action);
6082 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6083 * @param {String} id The value to search for
6086 findField : function(id){
6087 var items = this.getItems();
6088 var field = items.get(id);
6090 items.each(function(f){
6091 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6098 return field || null;
6101 * Mark fields in this form invalid in bulk.
6102 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6103 * @return {BasicForm} this
6105 markInvalid : function(errors){
6106 if(errors instanceof Array){
6107 for(var i = 0, len = errors.length; i < len; i++){
6108 var fieldError = errors[i];
6109 var f = this.findField(fieldError.id);
6111 f.markInvalid(fieldError.msg);
6117 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6118 field.markInvalid(errors[id]);
6122 //Roo.each(this.childForms || [], function (f) {
6123 // f.markInvalid(errors);
6130 * Set values for fields in this form in bulk.
6131 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6132 * @return {BasicForm} this
6134 setValues : function(values){
6135 if(values instanceof Array){ // array of objects
6136 for(var i = 0, len = values.length; i < len; i++){
6138 var f = this.findField(v.id);
6140 f.setValue(v.value);
6141 if(this.trackResetOnLoad){
6142 f.originalValue = f.getValue();
6146 }else{ // object hash
6149 if(typeof values[id] != 'function' && (field = this.findField(id))){
6151 if (field.setFromData &&
6153 field.displayField &&
6154 // combos' with local stores can
6155 // be queried via setValue()
6156 // to set their value..
6157 (field.store && !field.store.isLocal)
6161 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6162 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6163 field.setFromData(sd);
6166 field.setValue(values[id]);
6170 if(this.trackResetOnLoad){
6171 field.originalValue = field.getValue();
6177 //Roo.each(this.childForms || [], function (f) {
6178 // f.setValues(values);
6185 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6186 * they are returned as an array.
6187 * @param {Boolean} asString
6190 getValues : function(asString){
6191 //if (this.childForms) {
6192 // copy values from the child forms
6193 // Roo.each(this.childForms, function (f) {
6194 // this.setValues(f.getValues());
6200 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6201 if(asString === true){
6204 return Roo.urlDecode(fs);
6208 * Returns the fields in this form as an object with key/value pairs.
6209 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6212 getFieldValues : function(with_hidden)
6214 var items = this.getItems();
6216 items.each(function(f){
6220 var v = f.getValue();
6221 if (f.inputType =='radio') {
6222 if (typeof(ret[f.getName()]) == 'undefined') {
6223 ret[f.getName()] = ''; // empty..
6226 if (!f.el.dom.checked) {
6234 // not sure if this supported any more..
6235 if ((typeof(v) == 'object') && f.getRawValue) {
6236 v = f.getRawValue() ; // dates..
6238 // combo boxes where name != hiddenName...
6239 if (f.name != f.getName()) {
6240 ret[f.name] = f.getRawValue();
6242 ret[f.getName()] = v;
6249 * Clears all invalid messages in this form.
6250 * @return {BasicForm} this
6252 clearInvalid : function(){
6253 var items = this.getItems();
6255 items.each(function(f){
6266 * @return {BasicForm} this
6269 var items = this.getItems();
6270 items.each(function(f){
6274 Roo.each(this.childForms || [], function (f) {
6281 getItems : function()
6283 var r=new Roo.util.MixedCollection(false, function(o){
6284 return o.id || (o.id = Roo.id());
6286 var iter = function(el) {
6293 Roo.each(el.items,function(e) {
6312 * Ext JS Library 1.1.1
6313 * Copyright(c) 2006-2007, Ext JS, LLC.
6315 * Originally Released Under LGPL - original licence link has changed is not relivant.
6318 * <script type="text/javascript">
6321 * @class Roo.form.VTypes
6322 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6325 Roo.form.VTypes = function(){
6326 // closure these in so they are only created once.
6327 var alpha = /^[a-zA-Z_]+$/;
6328 var alphanum = /^[a-zA-Z0-9_]+$/;
6329 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6330 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6332 // All these messages and functions are configurable
6335 * The function used to validate email addresses
6336 * @param {String} value The email address
6338 'email' : function(v){
6339 return email.test(v);
6342 * The error text to display when the email validation function returns false
6345 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6347 * The keystroke filter mask to be applied on email input
6350 'emailMask' : /[a-z0-9_\.\-@]/i,
6353 * The function used to validate URLs
6354 * @param {String} value The URL
6356 'url' : function(v){
6360 * The error text to display when the url validation function returns false
6363 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6366 * The function used to validate alpha values
6367 * @param {String} value The value
6369 'alpha' : function(v){
6370 return alpha.test(v);
6373 * The error text to display when the alpha validation function returns false
6376 'alphaText' : 'This field should only contain letters and _',
6378 * The keystroke filter mask to be applied on alpha input
6381 'alphaMask' : /[a-z_]/i,
6384 * The function used to validate alphanumeric values
6385 * @param {String} value The value
6387 'alphanum' : function(v){
6388 return alphanum.test(v);
6391 * The error text to display when the alphanumeric validation function returns false
6394 'alphanumText' : 'This field should only contain letters, numbers and _',
6396 * The keystroke filter mask to be applied on alphanumeric input
6399 'alphanumMask' : /[a-z0-9_]/i
6409 * @class Roo.bootstrap.Input
6410 * @extends Roo.bootstrap.Component
6411 * Bootstrap Input class
6412 * @cfg {Boolean} disabled is it disabled
6413 * @cfg {String} fieldLabel - the label associated
6414 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6415 * @cfg {String} name name of the input
6416 * @cfg {string} fieldLabel - the label associated
6417 * @cfg {string} inputType - input / file submit ...
6418 * @cfg {string} placeholder - placeholder to put in text.
6419 * @cfg {string} before - input group add on before
6420 * @cfg {string} after - input group add on after
6421 * @cfg {string} size - (lg|sm) or leave empty..
6422 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6423 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6424 * @cfg {Number} md colspan out of 12 for computer-sized screens
6425 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6426 * @cfg {string} value default value of the input
6427 * @cfg {Number} labelWidth set the width of label (0-12)
6428 * @cfg {String} labelAlign (top|left)
6429 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6430 * @cfg {String} align (left|center|right) Default left
6431 * @cfg {Boolean} formatedValue (true | false) Default false
6435 * Create a new Input
6436 * @param {Object} config The config object
6439 Roo.bootstrap.Input = function(config){
6440 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6445 * Fires when this field receives input focus.
6446 * @param {Roo.form.Field} this
6451 * Fires when this field loses input focus.
6452 * @param {Roo.form.Field} this
6457 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6458 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6459 * @param {Roo.form.Field} this
6460 * @param {Roo.EventObject} e The event object
6465 * Fires just before the field blurs if the field value has changed.
6466 * @param {Roo.form.Field} this
6467 * @param {Mixed} newValue The new value
6468 * @param {Mixed} oldValue The original value
6473 * Fires after the field has been marked as invalid.
6474 * @param {Roo.form.Field} this
6475 * @param {String} msg The validation message
6480 * Fires after the field has been validated with no errors.
6481 * @param {Roo.form.Field} this
6486 * Fires after the key up
6487 * @param {Roo.form.Field} this
6488 * @param {Roo.EventObject} e The event Object
6494 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6496 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6497 automatic validation (defaults to "keyup").
6499 validationEvent : "keyup",
6501 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6503 validateOnBlur : true,
6505 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6507 validationDelay : 250,
6509 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6511 focusClass : "x-form-focus", // not needed???
6515 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6517 invalidClass : "has-error",
6520 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6522 selectOnFocus : false,
6525 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6529 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6534 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6536 disableKeyFilter : false,
6539 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6543 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6547 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6549 blankText : "This field is required",
6552 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6556 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6558 maxLength : Number.MAX_VALUE,
6560 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6562 minLengthText : "The minimum length for this field is {0}",
6564 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6566 maxLengthText : "The maximum length for this field is {0}",
6570 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6571 * If available, this function will be called only after the basic validators all return true, and will be passed the
6572 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6576 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6577 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6578 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6582 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6605 formatedValue : false,
6607 parentLabelAlign : function()
6610 while (parent.parent()) {
6611 parent = parent.parent();
6612 if (typeof(parent.labelAlign) !='undefined') {
6613 return parent.labelAlign;
6620 getAutoCreate : function(){
6622 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6628 if(this.inputType != 'hidden'){
6629 cfg.cls = 'form-group' //input-group
6635 type : this.inputType,
6637 cls : 'form-control',
6638 placeholder : this.placeholder || ''
6643 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6646 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6647 input.maxLength = this.maxLength;
6650 if (this.disabled) {
6651 input.disabled=true;
6654 if (this.readOnly) {
6655 input.readonly=true;
6659 input.name = this.name;
6662 input.cls += ' input-' + this.size;
6665 ['xs','sm','md','lg'].map(function(size){
6666 if (settings[size]) {
6667 cfg.cls += ' col-' + size + '-' + settings[size];
6671 var inputblock = input;
6673 if (this.before || this.after) {
6676 cls : 'input-group',
6679 if (this.before && typeof(this.before) == 'string') {
6681 inputblock.cn.push({
6683 cls : 'roo-input-before input-group-addon',
6687 if (this.before && typeof(this.before) == 'object') {
6688 this.before = Roo.factory(this.before);
6689 Roo.log(this.before);
6690 inputblock.cn.push({
6692 cls : 'roo-input-before input-group-' +
6693 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6697 inputblock.cn.push(input);
6699 if (this.after && typeof(this.after) == 'string') {
6700 inputblock.cn.push({
6702 cls : 'roo-input-after input-group-addon',
6706 if (this.after && typeof(this.after) == 'object') {
6707 this.after = Roo.factory(this.after);
6708 Roo.log(this.after);
6709 inputblock.cn.push({
6711 cls : 'roo-input-after input-group-' +
6712 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6717 if (align ==='left' && this.fieldLabel.length) {
6718 Roo.log("left and has label");
6724 cls : 'control-label col-sm-' + this.labelWidth,
6725 html : this.fieldLabel
6729 cls : "col-sm-" + (12 - this.labelWidth),
6736 } else if ( this.fieldLabel.length) {
6742 //cls : 'input-group-addon',
6743 html : this.fieldLabel
6753 Roo.log(" no label && no align");
6762 Roo.log('input-parentType: ' + this.parentType);
6764 if (this.parentType === 'Navbar' && this.parent().bar) {
6765 cfg.cls += ' navbar-form';
6773 * return the real input element.
6775 inputEl: function ()
6777 return this.el.select('input.form-control',true).first();
6779 setDisabled : function(v)
6781 var i = this.inputEl().dom;
6783 i.removeAttribute('disabled');
6787 i.setAttribute('disabled','true');
6789 initEvents : function()
6792 this.inputEl().on("keydown" , this.fireKey, this);
6793 this.inputEl().on("focus", this.onFocus, this);
6794 this.inputEl().on("blur", this.onBlur, this);
6796 this.inputEl().relayEvent('keyup', this);
6798 // reference to original value for reset
6799 this.originalValue = this.getValue();
6800 //Roo.form.TextField.superclass.initEvents.call(this);
6801 if(this.validationEvent == 'keyup'){
6802 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6803 this.inputEl().on('keyup', this.filterValidation, this);
6805 else if(this.validationEvent !== false){
6806 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6809 if(this.selectOnFocus){
6810 this.on("focus", this.preFocus, this);
6813 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6814 this.inputEl().on("keypress", this.filterKeys, this);
6817 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6818 this.el.on("click", this.autoSize, this);
6821 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6822 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6825 if (typeof(this.before) == 'object') {
6826 this.before.render(this.el.select('.roo-input-before',true).first());
6828 if (typeof(this.after) == 'object') {
6829 this.after.render(this.el.select('.roo-input-after',true).first());
6834 filterValidation : function(e){
6835 if(!e.isNavKeyPress()){
6836 this.validationTask.delay(this.validationDelay);
6840 * Validates the field value
6841 * @return {Boolean} True if the value is valid, else false
6843 validate : function(){
6844 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6845 if(this.disabled || this.validateValue(this.getRawValue())){
6846 this.clearInvalid();
6854 * Validates a value according to the field's validation rules and marks the field as invalid
6855 * if the validation fails
6856 * @param {Mixed} value The value to validate
6857 * @return {Boolean} True if the value is valid, else false
6859 validateValue : function(value){
6860 if(value.length < 1) { // if it's blank
6861 if(this.allowBlank){
6862 this.clearInvalid();
6865 this.markInvalid(this.blankText);
6869 if(value.length < this.minLength){
6870 this.markInvalid(String.format(this.minLengthText, this.minLength));
6873 if(value.length > this.maxLength){
6874 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6878 var vt = Roo.form.VTypes;
6879 if(!vt[this.vtype](value, this)){
6880 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6884 if(typeof this.validator == "function"){
6885 var msg = this.validator(value);
6887 this.markInvalid(msg);
6891 if(this.regex && !this.regex.test(value)){
6892 this.markInvalid(this.regexText);
6901 fireKey : function(e){
6902 //Roo.log('field ' + e.getKey());
6903 if(e.isNavKeyPress()){
6904 this.fireEvent("specialkey", this, e);
6907 focus : function (selectText){
6909 this.inputEl().focus();
6910 if(selectText === true){
6911 this.inputEl().dom.select();
6917 onFocus : function(){
6918 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6919 // this.el.addClass(this.focusClass);
6922 this.hasFocus = true;
6923 this.startValue = this.getValue();
6924 this.fireEvent("focus", this);
6928 beforeBlur : Roo.emptyFn,
6932 onBlur : function(){
6934 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6935 //this.el.removeClass(this.focusClass);
6937 this.hasFocus = false;
6938 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6941 var v = this.getValue();
6942 if(String(v) !== String(this.startValue)){
6943 this.fireEvent('change', this, v, this.startValue);
6945 this.fireEvent("blur", this);
6949 * Resets the current field value to the originally loaded value and clears any validation messages
6952 this.setValue(this.originalValue);
6953 this.clearInvalid();
6956 * Returns the name of the field
6957 * @return {Mixed} name The name field
6959 getName: function(){
6963 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6964 * @return {Mixed} value The field value
6966 getValue : function(){
6968 * Not sure why getValue and getRawValue are doing the same thing..
6971 if(this.formatedValue){
6975 return this.inputEl().getValue();
6978 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6979 * @return {Mixed} value The field value
6981 getRawValue : function(){
6982 var v = this.inputEl().getValue();
6988 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6989 * @param {Mixed} value The value to set
6991 setRawValue : function(v){
6992 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6995 selectText : function(start, end){
6996 var v = this.getRawValue();
6998 start = start === undefined ? 0 : start;
6999 end = end === undefined ? v.length : end;
7000 var d = this.inputEl().dom;
7001 if(d.setSelectionRange){
7002 d.setSelectionRange(start, end);
7003 }else if(d.createTextRange){
7004 var range = d.createTextRange();
7005 range.moveStart("character", start);
7006 range.moveEnd("character", v.length-end);
7013 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7014 * @param {Mixed} value The value to set
7016 setValue : function(v){
7019 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7025 processValue : function(value){
7026 if(this.stripCharsRe){
7027 var newValue = value.replace(this.stripCharsRe, '');
7028 if(newValue !== value){
7029 this.setRawValue(newValue);
7036 preFocus : function(){
7038 if(this.selectOnFocus){
7039 this.inputEl().dom.select();
7042 filterKeys : function(e){
7044 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7047 var c = e.getCharCode(), cc = String.fromCharCode(c);
7048 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7051 if(!this.maskRe.test(cc)){
7056 * Clear any invalid styles/messages for this field
7058 clearInvalid : function(){
7060 if(!this.el || this.preventMark){ // not rendered
7063 this.el.removeClass(this.invalidClass);
7065 switch(this.msgTarget){
7067 this.el.dom.qtip = '';
7070 this.el.dom.title = '';
7074 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7079 this.errorIcon.dom.qtip = '';
7080 this.errorIcon.hide();
7081 this.un('resize', this.alignErrorIcon, this);
7085 var t = Roo.getDom(this.msgTarget);
7087 t.style.display = 'none';
7091 this.fireEvent('valid', this);
7094 * Mark this field as invalid
7095 * @param {String} msg The validation message
7097 markInvalid : function(msg){
7098 if(!this.el || this.preventMark){ // not rendered
7101 this.el.addClass(this.invalidClass);
7103 msg = msg || this.invalidText;
7104 switch(this.msgTarget){
7106 this.el.dom.qtip = msg;
7107 this.el.dom.qclass = 'x-form-invalid-tip';
7108 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7109 Roo.QuickTips.enable();
7113 this.el.dom.title = msg;
7117 var elp = this.el.findParent('.x-form-element', 5, true);
7118 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7119 this.errorEl.setWidth(elp.getWidth(true)-20);
7121 this.errorEl.update(msg);
7122 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7125 if(!this.errorIcon){
7126 var elp = this.el.findParent('.x-form-element', 5, true);
7127 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7129 this.alignErrorIcon();
7130 this.errorIcon.dom.qtip = msg;
7131 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7132 this.errorIcon.show();
7133 this.on('resize', this.alignErrorIcon, this);
7136 var t = Roo.getDom(this.msgTarget);
7138 t.style.display = this.msgDisplay;
7142 this.fireEvent('invalid', this, msg);
7145 SafariOnKeyDown : function(event)
7147 // this is a workaround for a password hang bug on chrome/ webkit.
7149 var isSelectAll = false;
7151 if(this.inputEl().dom.selectionEnd > 0){
7152 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7154 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7155 event.preventDefault();
7160 if(isSelectAll){ // backspace and delete key
7162 event.preventDefault();
7163 // this is very hacky as keydown always get's upper case.
7165 var cc = String.fromCharCode(event.getCharCode());
7166 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7170 adjustWidth : function(tag, w){
7171 tag = tag.toLowerCase();
7172 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7173 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7177 if(tag == 'textarea'){
7180 }else if(Roo.isOpera){
7184 if(tag == 'textarea'){
7203 * @class Roo.bootstrap.TextArea
7204 * @extends Roo.bootstrap.Input
7205 * Bootstrap TextArea class
7206 * @cfg {Number} cols Specifies the visible width of a text area
7207 * @cfg {Number} rows Specifies the visible number of lines in a text area
7208 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7209 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7210 * @cfg {string} html text
7213 * Create a new TextArea
7214 * @param {Object} config The config object
7217 Roo.bootstrap.TextArea = function(config){
7218 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7222 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7232 getAutoCreate : function(){
7234 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7245 value : this.value || '',
7246 html: this.html || '',
7247 cls : 'form-control',
7248 placeholder : this.placeholder || ''
7252 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7253 input.maxLength = this.maxLength;
7257 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7261 input.cols = this.cols;
7264 if (this.readOnly) {
7265 input.readonly = true;
7269 input.name = this.name;
7273 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7277 ['xs','sm','md','lg'].map(function(size){
7278 if (settings[size]) {
7279 cfg.cls += ' col-' + size + '-' + settings[size];
7283 var inputblock = input;
7285 if (this.before || this.after) {
7288 cls : 'input-group',
7292 inputblock.cn.push({
7294 cls : 'input-group-addon',
7298 inputblock.cn.push(input);
7300 inputblock.cn.push({
7302 cls : 'input-group-addon',
7309 if (align ==='left' && this.fieldLabel.length) {
7310 Roo.log("left and has label");
7316 cls : 'control-label col-sm-' + this.labelWidth,
7317 html : this.fieldLabel
7321 cls : "col-sm-" + (12 - this.labelWidth),
7328 } else if ( this.fieldLabel.length) {
7334 //cls : 'input-group-addon',
7335 html : this.fieldLabel
7345 Roo.log(" no label && no align");
7355 if (this.disabled) {
7356 input.disabled=true;
7363 * return the real textarea element.
7365 inputEl: function ()
7367 return this.el.select('textarea.form-control',true).first();
7375 * trigger field - base class for combo..
7380 * @class Roo.bootstrap.TriggerField
7381 * @extends Roo.bootstrap.Input
7382 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7383 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7384 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7385 * for which you can provide a custom implementation. For example:
7387 var trigger = new Roo.bootstrap.TriggerField();
7388 trigger.onTriggerClick = myTriggerFn;
7389 trigger.applyTo('my-field');
7392 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7393 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7394 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7395 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7397 * Create a new TriggerField.
7398 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7399 * to the base TextField)
7401 Roo.bootstrap.TriggerField = function(config){
7402 this.mimicing = false;
7403 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7406 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7408 * @cfg {String} triggerClass A CSS class to apply to the trigger
7411 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7415 /** @cfg {Boolean} grow @hide */
7416 /** @cfg {Number} growMin @hide */
7417 /** @cfg {Number} growMax @hide */
7423 autoSize: Roo.emptyFn,
7430 actionMode : 'wrap',
7434 getAutoCreate : function(){
7436 var parent = this.parent();
7438 var align = this.labelAlign || this.parentLabelAlign();
7443 cls: 'form-group' //input-group
7450 type : this.inputType,
7451 cls : 'form-control',
7452 autocomplete: 'off',
7453 placeholder : this.placeholder || ''
7457 input.name = this.name;
7460 input.cls += ' input-' + this.size;
7463 if (this.disabled) {
7464 input.disabled=true;
7467 var inputblock = input;
7469 if (this.before || this.after) {
7472 cls : 'input-group',
7476 inputblock.cn.push({
7478 cls : 'input-group-addon',
7482 inputblock.cn.push(input);
7484 inputblock.cn.push({
7486 cls : 'input-group-addon',
7499 cls: 'form-hidden-field'
7507 Roo.log('multiple');
7515 cls: 'form-hidden-field'
7519 cls: 'select2-choices',
7523 cls: 'select2-search-field',
7536 cls: 'select2-container input-group',
7541 cls: 'typeahead typeahead-long dropdown-menu',
7542 style: 'display:none'
7550 cls : 'input-group-addon btn dropdown-toggle',
7558 cls: 'combobox-clear',
7572 combobox.cls += ' select2-container-multi';
7575 if (align ==='left' && this.fieldLabel.length) {
7577 Roo.log("left and has label");
7583 cls : 'control-label col-sm-' + this.labelWidth,
7584 html : this.fieldLabel
7588 cls : "col-sm-" + (12 - this.labelWidth),
7595 } else if ( this.fieldLabel.length) {
7601 //cls : 'input-group-addon',
7602 html : this.fieldLabel
7612 Roo.log(" no label && no align");
7619 ['xs','sm','md','lg'].map(function(size){
7620 if (settings[size]) {
7621 cfg.cls += ' col-' + size + '-' + settings[size];
7632 onResize : function(w, h){
7633 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7634 // if(typeof w == 'number'){
7635 // var x = w - this.trigger.getWidth();
7636 // this.inputEl().setWidth(this.adjustWidth('input', x));
7637 // this.trigger.setStyle('left', x+'px');
7642 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7645 getResizeEl : function(){
7646 return this.inputEl();
7650 getPositionEl : function(){
7651 return this.inputEl();
7655 alignErrorIcon : function(){
7656 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7660 initEvents : function(){
7662 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7663 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7665 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7666 if(this.hideTrigger){
7667 this.trigger.setDisplayed(false);
7669 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7673 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7676 //this.trigger.addClassOnOver('x-form-trigger-over');
7677 //this.trigger.addClassOnClick('x-form-trigger-click');
7680 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7685 initTrigger : function(){
7690 onDestroy : function(){
7692 this.trigger.removeAllListeners();
7693 // this.trigger.remove();
7696 // this.wrap.remove();
7698 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7702 onFocus : function(){
7703 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7706 this.wrap.addClass('x-trigger-wrap-focus');
7707 this.mimicing = true;
7708 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7709 if(this.monitorTab){
7710 this.el.on("keydown", this.checkTab, this);
7717 checkTab : function(e){
7718 if(e.getKey() == e.TAB){
7724 onBlur : function(){
7729 mimicBlur : function(e, t){
7731 if(!this.wrap.contains(t) && this.validateBlur()){
7738 triggerBlur : function(){
7739 this.mimicing = false;
7740 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7741 if(this.monitorTab){
7742 this.el.un("keydown", this.checkTab, this);
7744 //this.wrap.removeClass('x-trigger-wrap-focus');
7745 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7749 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7750 validateBlur : function(e, t){
7755 onDisable : function(){
7756 this.inputEl().dom.disabled = true;
7757 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7759 // this.wrap.addClass('x-item-disabled');
7764 onEnable : function(){
7765 this.inputEl().dom.disabled = false;
7766 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7768 // this.el.removeClass('x-item-disabled');
7773 onShow : function(){
7774 var ae = this.getActionEl();
7777 ae.dom.style.display = '';
7778 ae.dom.style.visibility = 'visible';
7784 onHide : function(){
7785 var ae = this.getActionEl();
7786 ae.dom.style.display = 'none';
7790 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7791 * by an implementing function.
7793 * @param {EventObject} e
7795 onTriggerClick : Roo.emptyFn
7799 * Ext JS Library 1.1.1
7800 * Copyright(c) 2006-2007, Ext JS, LLC.
7802 * Originally Released Under LGPL - original licence link has changed is not relivant.
7805 * <script type="text/javascript">
7810 * @class Roo.data.SortTypes
7812 * Defines the default sorting (casting?) comparison functions used when sorting data.
7814 Roo.data.SortTypes = {
7816 * Default sort that does nothing
7817 * @param {Mixed} s The value being converted
7818 * @return {Mixed} The comparison value
7825 * The regular expression used to strip tags
7829 stripTagsRE : /<\/?[^>]+>/gi,
7832 * Strips all HTML tags to sort on text only
7833 * @param {Mixed} s The value being converted
7834 * @return {String} The comparison value
7836 asText : function(s){
7837 return String(s).replace(this.stripTagsRE, "");
7841 * Strips all HTML tags to sort on text only - Case insensitive
7842 * @param {Mixed} s The value being converted
7843 * @return {String} The comparison value
7845 asUCText : function(s){
7846 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7850 * Case insensitive string
7851 * @param {Mixed} s The value being converted
7852 * @return {String} The comparison value
7854 asUCString : function(s) {
7855 return String(s).toUpperCase();
7860 * @param {Mixed} s The value being converted
7861 * @return {Number} The comparison value
7863 asDate : function(s) {
7867 if(s instanceof Date){
7870 return Date.parse(String(s));
7875 * @param {Mixed} s The value being converted
7876 * @return {Float} The comparison value
7878 asFloat : function(s) {
7879 var val = parseFloat(String(s).replace(/,/g, ""));
7880 if(isNaN(val)) val = 0;
7886 * @param {Mixed} s The value being converted
7887 * @return {Number} The comparison value
7889 asInt : function(s) {
7890 var val = parseInt(String(s).replace(/,/g, ""));
7891 if(isNaN(val)) val = 0;
7896 * Ext JS Library 1.1.1
7897 * Copyright(c) 2006-2007, Ext JS, LLC.
7899 * Originally Released Under LGPL - original licence link has changed is not relivant.
7902 * <script type="text/javascript">
7906 * @class Roo.data.Record
7907 * Instances of this class encapsulate both record <em>definition</em> information, and record
7908 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7909 * to access Records cached in an {@link Roo.data.Store} object.<br>
7911 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7912 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7915 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7917 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7918 * {@link #create}. The parameters are the same.
7919 * @param {Array} data An associative Array of data values keyed by the field name.
7920 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7921 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7922 * not specified an integer id is generated.
7924 Roo.data.Record = function(data, id){
7925 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7930 * Generate a constructor for a specific record layout.
7931 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7932 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7933 * Each field definition object may contain the following properties: <ul>
7934 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
7935 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7936 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7937 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7938 * is being used, then this is a string containing the javascript expression to reference the data relative to
7939 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7940 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7941 * this may be omitted.</p></li>
7942 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7943 * <ul><li>auto (Default, implies no conversion)</li>
7948 * <li>date</li></ul></p></li>
7949 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7950 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7951 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7952 * by the Reader into an object that will be stored in the Record. It is passed the
7953 * following parameters:<ul>
7954 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7956 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7958 * <br>usage:<br><pre><code>
7959 var TopicRecord = Roo.data.Record.create(
7960 {name: 'title', mapping: 'topic_title'},
7961 {name: 'author', mapping: 'username'},
7962 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7963 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7964 {name: 'lastPoster', mapping: 'user2'},
7965 {name: 'excerpt', mapping: 'post_text'}
7968 var myNewRecord = new TopicRecord({
7969 title: 'Do my job please',
7972 lastPost: new Date(),
7973 lastPoster: 'Animal',
7974 excerpt: 'No way dude!'
7976 myStore.add(myNewRecord);
7981 Roo.data.Record.create = function(o){
7983 f.superclass.constructor.apply(this, arguments);
7985 Roo.extend(f, Roo.data.Record);
7986 var p = f.prototype;
7987 p.fields = new Roo.util.MixedCollection(false, function(field){
7990 for(var i = 0, len = o.length; i < len; i++){
7991 p.fields.add(new Roo.data.Field(o[i]));
7993 f.getField = function(name){
7994 return p.fields.get(name);
7999 Roo.data.Record.AUTO_ID = 1000;
8000 Roo.data.Record.EDIT = 'edit';
8001 Roo.data.Record.REJECT = 'reject';
8002 Roo.data.Record.COMMIT = 'commit';
8004 Roo.data.Record.prototype = {
8006 * Readonly flag - true if this record has been modified.
8015 join : function(store){
8020 * Set the named field to the specified value.
8021 * @param {String} name The name of the field to set.
8022 * @param {Object} value The value to set the field to.
8024 set : function(name, value){
8025 if(this.data[name] == value){
8032 if(typeof this.modified[name] == 'undefined'){
8033 this.modified[name] = this.data[name];
8035 this.data[name] = value;
8036 if(!this.editing && this.store){
8037 this.store.afterEdit(this);
8042 * Get the value of the named field.
8043 * @param {String} name The name of the field to get the value of.
8044 * @return {Object} The value of the field.
8046 get : function(name){
8047 return this.data[name];
8051 beginEdit : function(){
8052 this.editing = true;
8057 cancelEdit : function(){
8058 this.editing = false;
8059 delete this.modified;
8063 endEdit : function(){
8064 this.editing = false;
8065 if(this.dirty && this.store){
8066 this.store.afterEdit(this);
8071 * Usually called by the {@link Roo.data.Store} which owns the Record.
8072 * Rejects all changes made to the Record since either creation, or the last commit operation.
8073 * Modified fields are reverted to their original values.
8075 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8076 * of reject operations.
8078 reject : function(){
8079 var m = this.modified;
8081 if(typeof m[n] != "function"){
8082 this.data[n] = m[n];
8086 delete this.modified;
8087 this.editing = false;
8089 this.store.afterReject(this);
8094 * Usually called by the {@link Roo.data.Store} which owns the Record.
8095 * Commits all changes made to the Record since either creation, or the last commit operation.
8097 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8098 * of commit operations.
8100 commit : function(){
8102 delete this.modified;
8103 this.editing = false;
8105 this.store.afterCommit(this);
8110 hasError : function(){
8111 return this.error != null;
8115 clearError : function(){
8120 * Creates a copy of this record.
8121 * @param {String} id (optional) A new record id if you don't want to use this record's id
8124 copy : function(newId) {
8125 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8129 * Ext JS Library 1.1.1
8130 * Copyright(c) 2006-2007, Ext JS, LLC.
8132 * Originally Released Under LGPL - original licence link has changed is not relivant.
8135 * <script type="text/javascript">
8141 * @class Roo.data.Store
8142 * @extends Roo.util.Observable
8143 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8144 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8146 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8147 * has no knowledge of the format of the data returned by the Proxy.<br>
8149 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8150 * instances from the data object. These records are cached and made available through accessor functions.
8152 * Creates a new Store.
8153 * @param {Object} config A config object containing the objects needed for the Store to access data,
8154 * and read the data into Records.
8156 Roo.data.Store = function(config){
8157 this.data = new Roo.util.MixedCollection(false);
8158 this.data.getKey = function(o){
8161 this.baseParams = {};
8168 "multisort" : "_multisort"
8171 if(config && config.data){
8172 this.inlineData = config.data;
8176 Roo.apply(this, config);
8178 if(this.reader){ // reader passed
8179 this.reader = Roo.factory(this.reader, Roo.data);
8180 this.reader.xmodule = this.xmodule || false;
8181 if(!this.recordType){
8182 this.recordType = this.reader.recordType;
8184 if(this.reader.onMetaChange){
8185 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8189 if(this.recordType){
8190 this.fields = this.recordType.prototype.fields;
8196 * @event datachanged
8197 * Fires when the data cache has changed, and a widget which is using this Store
8198 * as a Record cache should refresh its view.
8199 * @param {Store} this
8204 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8205 * @param {Store} this
8206 * @param {Object} meta The JSON metadata
8211 * Fires when Records have been added to the Store
8212 * @param {Store} this
8213 * @param {Roo.data.Record[]} records The array of Records added
8214 * @param {Number} index The index at which the record(s) were added
8219 * Fires when a Record has been removed from the Store
8220 * @param {Store} this
8221 * @param {Roo.data.Record} record The Record that was removed
8222 * @param {Number} index The index at which the record was removed
8227 * Fires when a Record has been updated
8228 * @param {Store} this
8229 * @param {Roo.data.Record} record The Record that was updated
8230 * @param {String} operation The update operation being performed. Value may be one of:
8232 Roo.data.Record.EDIT
8233 Roo.data.Record.REJECT
8234 Roo.data.Record.COMMIT
8240 * Fires when the data cache has been cleared.
8241 * @param {Store} this
8246 * Fires before a request is made for a new data object. If the beforeload handler returns false
8247 * the load action will be canceled.
8248 * @param {Store} this
8249 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8253 * @event beforeloadadd
8254 * Fires after a new set of Records has been loaded.
8255 * @param {Store} this
8256 * @param {Roo.data.Record[]} records The Records that were loaded
8257 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8259 beforeloadadd : true,
8262 * Fires after a new set of Records has been loaded, before they are added to the store.
8263 * @param {Store} this
8264 * @param {Roo.data.Record[]} records The Records that were loaded
8265 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8266 * @params {Object} return from reader
8270 * @event loadexception
8271 * Fires if an exception occurs in the Proxy during loading.
8272 * Called with the signature of the Proxy's "loadexception" event.
8273 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8276 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8277 * @param {Object} load options
8278 * @param {Object} jsonData from your request (normally this contains the Exception)
8280 loadexception : true
8284 this.proxy = Roo.factory(this.proxy, Roo.data);
8285 this.proxy.xmodule = this.xmodule || false;
8286 this.relayEvents(this.proxy, ["loadexception"]);
8288 this.sortToggle = {};
8289 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8291 Roo.data.Store.superclass.constructor.call(this);
8293 if(this.inlineData){
8294 this.loadData(this.inlineData);
8295 delete this.inlineData;
8299 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8301 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8302 * without a remote query - used by combo/forms at present.
8306 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8309 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8312 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8313 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8316 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8317 * on any HTTP request
8320 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8323 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8327 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8328 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8333 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8334 * loaded or when a record is removed. (defaults to false).
8336 pruneModifiedRecords : false,
8342 * Add Records to the Store and fires the add event.
8343 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8345 add : function(records){
8346 records = [].concat(records);
8347 for(var i = 0, len = records.length; i < len; i++){
8348 records[i].join(this);
8350 var index = this.data.length;
8351 this.data.addAll(records);
8352 this.fireEvent("add", this, records, index);
8356 * Remove a Record from the Store and fires the remove event.
8357 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8359 remove : function(record){
8360 var index = this.data.indexOf(record);
8361 this.data.removeAt(index);
8362 if(this.pruneModifiedRecords){
8363 this.modified.remove(record);
8365 this.fireEvent("remove", this, record, index);
8369 * Remove all Records from the Store and fires the clear event.
8371 removeAll : function(){
8373 if(this.pruneModifiedRecords){
8376 this.fireEvent("clear", this);
8380 * Inserts Records to the Store at the given index and fires the add event.
8381 * @param {Number} index The start index at which to insert the passed Records.
8382 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8384 insert : function(index, records){
8385 records = [].concat(records);
8386 for(var i = 0, len = records.length; i < len; i++){
8387 this.data.insert(index, records[i]);
8388 records[i].join(this);
8390 this.fireEvent("add", this, records, index);
8394 * Get the index within the cache of the passed Record.
8395 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8396 * @return {Number} The index of the passed Record. Returns -1 if not found.
8398 indexOf : function(record){
8399 return this.data.indexOf(record);
8403 * Get the index within the cache of the Record with the passed id.
8404 * @param {String} id The id of the Record to find.
8405 * @return {Number} The index of the Record. Returns -1 if not found.
8407 indexOfId : function(id){
8408 return this.data.indexOfKey(id);
8412 * Get the Record with the specified id.
8413 * @param {String} id The id of the Record to find.
8414 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8416 getById : function(id){
8417 return this.data.key(id);
8421 * Get the Record at the specified index.
8422 * @param {Number} index The index of the Record to find.
8423 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8425 getAt : function(index){
8426 return this.data.itemAt(index);
8430 * Returns a range of Records between specified indices.
8431 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8432 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8433 * @return {Roo.data.Record[]} An array of Records
8435 getRange : function(start, end){
8436 return this.data.getRange(start, end);
8440 storeOptions : function(o){
8441 o = Roo.apply({}, o);
8444 this.lastOptions = o;
8448 * Loads the Record cache from the configured Proxy using the configured Reader.
8450 * If using remote paging, then the first load call must specify the <em>start</em>
8451 * and <em>limit</em> properties in the options.params property to establish the initial
8452 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8454 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8455 * and this call will return before the new data has been loaded. Perform any post-processing
8456 * in a callback function, or in a "load" event handler.</strong>
8458 * @param {Object} options An object containing properties which control loading options:<ul>
8459 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8460 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8461 * passed the following arguments:<ul>
8462 * <li>r : Roo.data.Record[]</li>
8463 * <li>options: Options object from the load call</li>
8464 * <li>success: Boolean success indicator</li></ul></li>
8465 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8466 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8469 load : function(options){
8470 options = options || {};
8471 if(this.fireEvent("beforeload", this, options) !== false){
8472 this.storeOptions(options);
8473 var p = Roo.apply(options.params || {}, this.baseParams);
8474 // if meta was not loaded from remote source.. try requesting it.
8475 if (!this.reader.metaFromRemote) {
8478 if(this.sortInfo && this.remoteSort){
8479 var pn = this.paramNames;
8480 p[pn["sort"]] = this.sortInfo.field;
8481 p[pn["dir"]] = this.sortInfo.direction;
8483 if (this.multiSort) {
8484 var pn = this.paramNames;
8485 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8488 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8493 * Reloads the Record cache from the configured Proxy using the configured Reader and
8494 * the options from the last load operation performed.
8495 * @param {Object} options (optional) An object containing properties which may override the options
8496 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8497 * the most recently used options are reused).
8499 reload : function(options){
8500 this.load(Roo.applyIf(options||{}, this.lastOptions));
8504 // Called as a callback by the Reader during a load operation.
8505 loadRecords : function(o, options, success){
8506 if(!o || success === false){
8507 if(success !== false){
8508 this.fireEvent("load", this, [], options, o);
8510 if(options.callback){
8511 options.callback.call(options.scope || this, [], options, false);
8515 // if data returned failure - throw an exception.
8516 if (o.success === false) {
8517 // show a message if no listener is registered.
8518 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8519 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8521 // loadmask wil be hooked into this..
8522 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8525 var r = o.records, t = o.totalRecords || r.length;
8527 this.fireEvent("beforeloadadd", this, r, options, o);
8529 if(!options || options.add !== true){
8530 if(this.pruneModifiedRecords){
8533 for(var i = 0, len = r.length; i < len; i++){
8537 this.data = this.snapshot;
8538 delete this.snapshot;
8541 this.data.addAll(r);
8542 this.totalLength = t;
8544 this.fireEvent("datachanged", this);
8546 this.totalLength = Math.max(t, this.data.length+r.length);
8549 this.fireEvent("load", this, r, options, o);
8550 if(options.callback){
8551 options.callback.call(options.scope || this, r, options, true);
8557 * Loads data from a passed data block. A Reader which understands the format of the data
8558 * must have been configured in the constructor.
8559 * @param {Object} data The data block from which to read the Records. The format of the data expected
8560 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8561 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8563 loadData : function(o, append){
8564 var r = this.reader.readRecords(o);
8565 this.loadRecords(r, {add: append}, true);
8569 * Gets the number of cached records.
8571 * <em>If using paging, this may not be the total size of the dataset. If the data object
8572 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8573 * the data set size</em>
8575 getCount : function(){
8576 return this.data.length || 0;
8580 * Gets the total number of records in the dataset as returned by the server.
8582 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8583 * the dataset size</em>
8585 getTotalCount : function(){
8586 return this.totalLength || 0;
8590 * Returns the sort state of the Store as an object with two properties:
8592 field {String} The name of the field by which the Records are sorted
8593 direction {String} The sort order, "ASC" or "DESC"
8596 getSortState : function(){
8597 return this.sortInfo;
8601 applySort : function(){
8602 if(this.sortInfo && !this.remoteSort){
8603 var s = this.sortInfo, f = s.field;
8604 var st = this.fields.get(f).sortType;
8605 var fn = function(r1, r2){
8606 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8607 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8609 this.data.sort(s.direction, fn);
8610 if(this.snapshot && this.snapshot != this.data){
8611 this.snapshot.sort(s.direction, fn);
8617 * Sets the default sort column and order to be used by the next load operation.
8618 * @param {String} fieldName The name of the field to sort by.
8619 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8621 setDefaultSort : function(field, dir){
8622 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8627 * If remote sorting is used, the sort is performed on the server, and the cache is
8628 * reloaded. If local sorting is used, the cache is sorted internally.
8629 * @param {String} fieldName The name of the field to sort by.
8630 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8632 sort : function(fieldName, dir){
8633 var f = this.fields.get(fieldName);
8635 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8637 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8638 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8643 this.sortToggle[f.name] = dir;
8644 this.sortInfo = {field: f.name, direction: dir};
8645 if(!this.remoteSort){
8647 this.fireEvent("datachanged", this);
8649 this.load(this.lastOptions);
8654 * Calls the specified function for each of the Records in the cache.
8655 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8656 * Returning <em>false</em> aborts and exits the iteration.
8657 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8659 each : function(fn, scope){
8660 this.data.each(fn, scope);
8664 * Gets all records modified since the last commit. Modified records are persisted across load operations
8665 * (e.g., during paging).
8666 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8668 getModifiedRecords : function(){
8669 return this.modified;
8673 createFilterFn : function(property, value, anyMatch){
8674 if(!value.exec){ // not a regex
8675 value = String(value);
8676 if(value.length == 0){
8679 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8682 return value.test(r.data[property]);
8687 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8688 * @param {String} property A field on your records
8689 * @param {Number} start The record index to start at (defaults to 0)
8690 * @param {Number} end The last record index to include (defaults to length - 1)
8691 * @return {Number} The sum
8693 sum : function(property, start, end){
8694 var rs = this.data.items, v = 0;
8696 end = (end || end === 0) ? end : rs.length-1;
8698 for(var i = start; i <= end; i++){
8699 v += (rs[i].data[property] || 0);
8705 * Filter the records by a specified property.
8706 * @param {String} field A field on your records
8707 * @param {String/RegExp} value Either a string that the field
8708 * should start with or a RegExp to test against the field
8709 * @param {Boolean} anyMatch True to match any part not just the beginning
8711 filter : function(property, value, anyMatch){
8712 var fn = this.createFilterFn(property, value, anyMatch);
8713 return fn ? this.filterBy(fn) : this.clearFilter();
8717 * Filter by a function. The specified function will be called with each
8718 * record in this data source. If the function returns true the record is included,
8719 * otherwise it is filtered.
8720 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8721 * @param {Object} scope (optional) The scope of the function (defaults to this)
8723 filterBy : function(fn, scope){
8724 this.snapshot = this.snapshot || this.data;
8725 this.data = this.queryBy(fn, scope||this);
8726 this.fireEvent("datachanged", this);
8730 * Query the records by a specified property.
8731 * @param {String} field A field on your records
8732 * @param {String/RegExp} value Either a string that the field
8733 * should start with or a RegExp to test against the field
8734 * @param {Boolean} anyMatch True to match any part not just the beginning
8735 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8737 query : function(property, value, anyMatch){
8738 var fn = this.createFilterFn(property, value, anyMatch);
8739 return fn ? this.queryBy(fn) : this.data.clone();
8743 * Query by a function. The specified function will be called with each
8744 * record in this data source. If the function returns true the record is included
8746 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8747 * @param {Object} scope (optional) The scope of the function (defaults to this)
8748 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8750 queryBy : function(fn, scope){
8751 var data = this.snapshot || this.data;
8752 return data.filterBy(fn, scope||this);
8756 * Collects unique values for a particular dataIndex from this store.
8757 * @param {String} dataIndex The property to collect
8758 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8759 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8760 * @return {Array} An array of the unique values
8762 collect : function(dataIndex, allowNull, bypassFilter){
8763 var d = (bypassFilter === true && this.snapshot) ?
8764 this.snapshot.items : this.data.items;
8765 var v, sv, r = [], l = {};
8766 for(var i = 0, len = d.length; i < len; i++){
8767 v = d[i].data[dataIndex];
8769 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8778 * Revert to a view of the Record cache with no filtering applied.
8779 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8781 clearFilter : function(suppressEvent){
8782 if(this.snapshot && this.snapshot != this.data){
8783 this.data = this.snapshot;
8784 delete this.snapshot;
8785 if(suppressEvent !== true){
8786 this.fireEvent("datachanged", this);
8792 afterEdit : function(record){
8793 if(this.modified.indexOf(record) == -1){
8794 this.modified.push(record);
8796 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8800 afterReject : function(record){
8801 this.modified.remove(record);
8802 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8806 afterCommit : function(record){
8807 this.modified.remove(record);
8808 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8812 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8813 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8815 commitChanges : function(){
8816 var m = this.modified.slice(0);
8818 for(var i = 0, len = m.length; i < len; i++){
8824 * Cancel outstanding changes on all changed records.
8826 rejectChanges : function(){
8827 var m = this.modified.slice(0);
8829 for(var i = 0, len = m.length; i < len; i++){
8834 onMetaChange : function(meta, rtype, o){
8835 this.recordType = rtype;
8836 this.fields = rtype.prototype.fields;
8837 delete this.snapshot;
8838 this.sortInfo = meta.sortInfo || this.sortInfo;
8840 this.fireEvent('metachange', this, this.reader.meta);
8843 moveIndex : function(data, type)
8845 var index = this.indexOf(data);
8847 var newIndex = index + type;
8851 this.insert(newIndex, data);
8856 * Ext JS Library 1.1.1
8857 * Copyright(c) 2006-2007, Ext JS, LLC.
8859 * Originally Released Under LGPL - original licence link has changed is not relivant.
8862 * <script type="text/javascript">
8866 * @class Roo.data.SimpleStore
8867 * @extends Roo.data.Store
8868 * Small helper class to make creating Stores from Array data easier.
8869 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8870 * @cfg {Array} fields An array of field definition objects, or field name strings.
8871 * @cfg {Array} data The multi-dimensional array of data
8873 * @param {Object} config
8875 Roo.data.SimpleStore = function(config){
8876 Roo.data.SimpleStore.superclass.constructor.call(this, {
8878 reader: new Roo.data.ArrayReader({
8881 Roo.data.Record.create(config.fields)
8883 proxy : new Roo.data.MemoryProxy(config.data)
8887 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8889 * Ext JS Library 1.1.1
8890 * Copyright(c) 2006-2007, Ext JS, LLC.
8892 * Originally Released Under LGPL - original licence link has changed is not relivant.
8895 * <script type="text/javascript">
8900 * @extends Roo.data.Store
8901 * @class Roo.data.JsonStore
8902 * Small helper class to make creating Stores for JSON data easier. <br/>
8904 var store = new Roo.data.JsonStore({
8905 url: 'get-images.php',
8907 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8910 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8911 * JsonReader and HttpProxy (unless inline data is provided).</b>
8912 * @cfg {Array} fields An array of field definition objects, or field name strings.
8914 * @param {Object} config
8916 Roo.data.JsonStore = function(c){
8917 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8918 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8919 reader: new Roo.data.JsonReader(c, c.fields)
8922 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8924 * Ext JS Library 1.1.1
8925 * Copyright(c) 2006-2007, Ext JS, LLC.
8927 * Originally Released Under LGPL - original licence link has changed is not relivant.
8930 * <script type="text/javascript">
8934 Roo.data.Field = function(config){
8935 if(typeof config == "string"){
8936 config = {name: config};
8938 Roo.apply(this, config);
8944 var st = Roo.data.SortTypes;
8945 // named sortTypes are supported, here we look them up
8946 if(typeof this.sortType == "string"){
8947 this.sortType = st[this.sortType];
8950 // set default sortType for strings and dates
8954 this.sortType = st.asUCString;
8957 this.sortType = st.asDate;
8960 this.sortType = st.none;
8965 var stripRe = /[\$,%]/g;
8967 // prebuilt conversion function for this field, instead of
8968 // switching every time we're reading a value
8970 var cv, dateFormat = this.dateFormat;
8975 cv = function(v){ return v; };
8978 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8982 return v !== undefined && v !== null && v !== '' ?
8983 parseInt(String(v).replace(stripRe, ""), 10) : '';
8988 return v !== undefined && v !== null && v !== '' ?
8989 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8994 cv = function(v){ return v === true || v === "true" || v == 1; };
9001 if(v instanceof Date){
9005 if(dateFormat == "timestamp"){
9006 return new Date(v*1000);
9008 return Date.parseDate(v, dateFormat);
9010 var parsed = Date.parse(v);
9011 return parsed ? new Date(parsed) : null;
9020 Roo.data.Field.prototype = {
9028 * Ext JS Library 1.1.1
9029 * Copyright(c) 2006-2007, Ext JS, LLC.
9031 * Originally Released Under LGPL - original licence link has changed is not relivant.
9034 * <script type="text/javascript">
9037 // Base class for reading structured data from a data source. This class is intended to be
9038 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9041 * @class Roo.data.DataReader
9042 * Base class for reading structured data from a data source. This class is intended to be
9043 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9046 Roo.data.DataReader = function(meta, recordType){
9050 this.recordType = recordType instanceof Array ?
9051 Roo.data.Record.create(recordType) : recordType;
9054 Roo.data.DataReader.prototype = {
9056 * Create an empty record
9057 * @param {Object} data (optional) - overlay some values
9058 * @return {Roo.data.Record} record created.
9060 newRow : function(d) {
9062 this.recordType.prototype.fields.each(function(c) {
9064 case 'int' : da[c.name] = 0; break;
9065 case 'date' : da[c.name] = new Date(); break;
9066 case 'float' : da[c.name] = 0.0; break;
9067 case 'boolean' : da[c.name] = false; break;
9068 default : da[c.name] = ""; break;
9072 return new this.recordType(Roo.apply(da, d));
9077 * Ext JS Library 1.1.1
9078 * Copyright(c) 2006-2007, Ext JS, LLC.
9080 * Originally Released Under LGPL - original licence link has changed is not relivant.
9083 * <script type="text/javascript">
9087 * @class Roo.data.DataProxy
9088 * @extends Roo.data.Observable
9089 * This class is an abstract base class for implementations which provide retrieval of
9090 * unformatted data objects.<br>
9092 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9093 * (of the appropriate type which knows how to parse the data object) to provide a block of
9094 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9096 * Custom implementations must implement the load method as described in
9097 * {@link Roo.data.HttpProxy#load}.
9099 Roo.data.DataProxy = function(){
9103 * Fires before a network request is made to retrieve a data object.
9104 * @param {Object} This DataProxy object.
9105 * @param {Object} params The params parameter to the load function.
9110 * Fires before the load method's callback is called.
9111 * @param {Object} This DataProxy object.
9112 * @param {Object} o The data object.
9113 * @param {Object} arg The callback argument object passed to the load function.
9117 * @event loadexception
9118 * Fires if an Exception occurs during data retrieval.
9119 * @param {Object} This DataProxy object.
9120 * @param {Object} o The data object.
9121 * @param {Object} arg The callback argument object passed to the load function.
9122 * @param {Object} e The Exception.
9124 loadexception : true
9126 Roo.data.DataProxy.superclass.constructor.call(this);
9129 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9132 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9136 * Ext JS Library 1.1.1
9137 * Copyright(c) 2006-2007, Ext JS, LLC.
9139 * Originally Released Under LGPL - original licence link has changed is not relivant.
9142 * <script type="text/javascript">
9145 * @class Roo.data.MemoryProxy
9146 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9147 * to the Reader when its load method is called.
9149 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9151 Roo.data.MemoryProxy = function(data){
9155 Roo.data.MemoryProxy.superclass.constructor.call(this);
9159 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9161 * Load data from the requested source (in this case an in-memory
9162 * data object passed to the constructor), read the data object into
9163 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9164 * process that block using the passed callback.
9165 * @param {Object} params This parameter is not used by the MemoryProxy class.
9166 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9167 * object into a block of Roo.data.Records.
9168 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9169 * The function must be passed <ul>
9170 * <li>The Record block object</li>
9171 * <li>The "arg" argument from the load function</li>
9172 * <li>A boolean success indicator</li>
9174 * @param {Object} scope The scope in which to call the callback
9175 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9177 load : function(params, reader, callback, scope, arg){
9178 params = params || {};
9181 result = reader.readRecords(this.data);
9183 this.fireEvent("loadexception", this, arg, null, e);
9184 callback.call(scope, null, arg, false);
9187 callback.call(scope, result, arg, true);
9191 update : function(params, records){
9196 * Ext JS Library 1.1.1
9197 * Copyright(c) 2006-2007, Ext JS, LLC.
9199 * Originally Released Under LGPL - original licence link has changed is not relivant.
9202 * <script type="text/javascript">
9205 * @class Roo.data.HttpProxy
9206 * @extends Roo.data.DataProxy
9207 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9208 * configured to reference a certain URL.<br><br>
9210 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9211 * from which the running page was served.<br><br>
9213 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9215 * Be aware that to enable the browser to parse an XML document, the server must set
9216 * the Content-Type header in the HTTP response to "text/xml".
9218 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9219 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9220 * will be used to make the request.
9222 Roo.data.HttpProxy = function(conn){
9223 Roo.data.HttpProxy.superclass.constructor.call(this);
9224 // is conn a conn config or a real conn?
9226 this.useAjax = !conn || !conn.events;
9230 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9231 // thse are take from connection...
9234 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9237 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9238 * extra parameters to each request made by this object. (defaults to undefined)
9241 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9242 * to each request made by this object. (defaults to undefined)
9245 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
9248 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9251 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9257 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9261 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9262 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9263 * a finer-grained basis than the DataProxy events.
9265 getConnection : function(){
9266 return this.useAjax ? Roo.Ajax : this.conn;
9270 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9271 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9272 * process that block using the passed callback.
9273 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9274 * for the request to the remote server.
9275 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9276 * object into a block of Roo.data.Records.
9277 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9278 * The function must be passed <ul>
9279 * <li>The Record block object</li>
9280 * <li>The "arg" argument from the load function</li>
9281 * <li>A boolean success indicator</li>
9283 * @param {Object} scope The scope in which to call the callback
9284 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9286 load : function(params, reader, callback, scope, arg){
9287 if(this.fireEvent("beforeload", this, params) !== false){
9289 params : params || {},
9291 callback : callback,
9296 callback : this.loadResponse,
9300 Roo.applyIf(o, this.conn);
9301 if(this.activeRequest){
9302 Roo.Ajax.abort(this.activeRequest);
9304 this.activeRequest = Roo.Ajax.request(o);
9306 this.conn.request(o);
9309 callback.call(scope||this, null, arg, false);
9314 loadResponse : function(o, success, response){
9315 delete this.activeRequest;
9317 this.fireEvent("loadexception", this, o, response);
9318 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9323 result = o.reader.read(response);
9325 this.fireEvent("loadexception", this, o, response, e);
9326 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9330 this.fireEvent("load", this, o, o.request.arg);
9331 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9335 update : function(dataSet){
9340 updateResponse : function(dataSet){
9345 * Ext JS Library 1.1.1
9346 * Copyright(c) 2006-2007, Ext JS, LLC.
9348 * Originally Released Under LGPL - original licence link has changed is not relivant.
9351 * <script type="text/javascript">
9355 * @class Roo.data.ScriptTagProxy
9356 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9357 * other than the originating domain of the running page.<br><br>
9359 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
9360 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9362 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9363 * source code that is used as the source inside a <script> tag.<br><br>
9365 * In order for the browser to process the returned data, the server must wrap the data object
9366 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9367 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9368 * depending on whether the callback name was passed:
9371 boolean scriptTag = false;
9372 String cb = request.getParameter("callback");
9375 response.setContentType("text/javascript");
9377 response.setContentType("application/x-json");
9379 Writer out = response.getWriter();
9381 out.write(cb + "(");
9383 out.print(dataBlock.toJsonString());
9390 * @param {Object} config A configuration object.
9392 Roo.data.ScriptTagProxy = function(config){
9393 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9394 Roo.apply(this, config);
9395 this.head = document.getElementsByTagName("head")[0];
9398 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9400 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9402 * @cfg {String} url The URL from which to request the data object.
9405 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9409 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9410 * the server the name of the callback function set up by the load call to process the returned data object.
9411 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9412 * javascript output which calls this named function passing the data object as its only parameter.
9414 callbackParam : "callback",
9416 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9417 * name to the request.
9422 * Load data from the configured URL, read the data object into
9423 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9424 * process that block using the passed callback.
9425 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9426 * for the request to the remote server.
9427 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9428 * object into a block of Roo.data.Records.
9429 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9430 * The function must be passed <ul>
9431 * <li>The Record block object</li>
9432 * <li>The "arg" argument from the load function</li>
9433 * <li>A boolean success indicator</li>
9435 * @param {Object} scope The scope in which to call the callback
9436 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9438 load : function(params, reader, callback, scope, arg){
9439 if(this.fireEvent("beforeload", this, params) !== false){
9441 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9444 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9446 url += "&_dc=" + (new Date().getTime());
9448 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9451 cb : "stcCallback"+transId,
9452 scriptId : "stcScript"+transId,
9456 callback : callback,
9462 window[trans.cb] = function(o){
9463 conn.handleResponse(o, trans);
9466 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9468 if(this.autoAbort !== false){
9472 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9474 var script = document.createElement("script");
9475 script.setAttribute("src", url);
9476 script.setAttribute("type", "text/javascript");
9477 script.setAttribute("id", trans.scriptId);
9478 this.head.appendChild(script);
9482 callback.call(scope||this, null, arg, false);
9487 isLoading : function(){
9488 return this.trans ? true : false;
9492 * Abort the current server request.
9495 if(this.isLoading()){
9496 this.destroyTrans(this.trans);
9501 destroyTrans : function(trans, isLoaded){
9502 this.head.removeChild(document.getElementById(trans.scriptId));
9503 clearTimeout(trans.timeoutId);
9505 window[trans.cb] = undefined;
9507 delete window[trans.cb];
9510 // if hasn't been loaded, wait for load to remove it to prevent script error
9511 window[trans.cb] = function(){
9512 window[trans.cb] = undefined;
9514 delete window[trans.cb];
9521 handleResponse : function(o, trans){
9523 this.destroyTrans(trans, true);
9526 result = trans.reader.readRecords(o);
9528 this.fireEvent("loadexception", this, o, trans.arg, e);
9529 trans.callback.call(trans.scope||window, null, trans.arg, false);
9532 this.fireEvent("load", this, o, trans.arg);
9533 trans.callback.call(trans.scope||window, result, trans.arg, true);
9537 handleFailure : function(trans){
9539 this.destroyTrans(trans, false);
9540 this.fireEvent("loadexception", this, null, trans.arg);
9541 trans.callback.call(trans.scope||window, null, trans.arg, false);
9545 * Ext JS Library 1.1.1
9546 * Copyright(c) 2006-2007, Ext JS, LLC.
9548 * Originally Released Under LGPL - original licence link has changed is not relivant.
9551 * <script type="text/javascript">
9555 * @class Roo.data.JsonReader
9556 * @extends Roo.data.DataReader
9557 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9558 * based on mappings in a provided Roo.data.Record constructor.
9560 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9561 * in the reply previously.
9566 var RecordDef = Roo.data.Record.create([
9567 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9568 {name: 'occupation'} // This field will use "occupation" as the mapping.
9570 var myReader = new Roo.data.JsonReader({
9571 totalProperty: "results", // The property which contains the total dataset size (optional)
9572 root: "rows", // The property which contains an Array of row objects
9573 id: "id" // The property within each row object that provides an ID for the record (optional)
9577 * This would consume a JSON file like this:
9579 { 'results': 2, 'rows': [
9580 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9581 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9584 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9585 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9586 * paged from the remote server.
9587 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9588 * @cfg {String} root name of the property which contains the Array of row objects.
9589 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9591 * Create a new JsonReader
9592 * @param {Object} meta Metadata configuration options
9593 * @param {Object} recordType Either an Array of field definition objects,
9594 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9596 Roo.data.JsonReader = function(meta, recordType){
9599 // set some defaults:
9601 totalProperty: 'total',
9602 successProperty : 'success',
9607 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9609 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9612 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9613 * Used by Store query builder to append _requestMeta to params.
9616 metaFromRemote : false,
9618 * This method is only used by a DataProxy which has retrieved data from a remote server.
9619 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9620 * @return {Object} data A data block which is used by an Roo.data.Store object as
9621 * a cache of Roo.data.Records.
9623 read : function(response){
9624 var json = response.responseText;
9626 var o = /* eval:var:o */ eval("("+json+")");
9628 throw {message: "JsonReader.read: Json object not found"};
9634 this.metaFromRemote = true;
9635 this.meta = o.metaData;
9636 this.recordType = Roo.data.Record.create(o.metaData.fields);
9637 this.onMetaChange(this.meta, this.recordType, o);
9639 return this.readRecords(o);
9642 // private function a store will implement
9643 onMetaChange : function(meta, recordType, o){
9650 simpleAccess: function(obj, subsc) {
9657 getJsonAccessor: function(){
9659 return function(expr) {
9661 return(re.test(expr))
9662 ? new Function("obj", "return obj." + expr)
9672 * Create a data block containing Roo.data.Records from an XML document.
9673 * @param {Object} o An object which contains an Array of row objects in the property specified
9674 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9675 * which contains the total size of the dataset.
9676 * @return {Object} data A data block which is used by an Roo.data.Store object as
9677 * a cache of Roo.data.Records.
9679 readRecords : function(o){
9681 * After any data loads, the raw JSON data is available for further custom processing.
9685 var s = this.meta, Record = this.recordType,
9686 f = Record.prototype.fields, fi = f.items, fl = f.length;
9688 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9690 if(s.totalProperty) {
9691 this.getTotal = this.getJsonAccessor(s.totalProperty);
9693 if(s.successProperty) {
9694 this.getSuccess = this.getJsonAccessor(s.successProperty);
9696 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9698 var g = this.getJsonAccessor(s.id);
9699 this.getId = function(rec) {
9701 return (r === undefined || r === "") ? null : r;
9704 this.getId = function(){return null;};
9707 for(var jj = 0; jj < fl; jj++){
9709 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9710 this.ef[jj] = this.getJsonAccessor(map);
9714 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9715 if(s.totalProperty){
9716 var vt = parseInt(this.getTotal(o), 10);
9721 if(s.successProperty){
9722 var vs = this.getSuccess(o);
9723 if(vs === false || vs === 'false'){
9728 for(var i = 0; i < c; i++){
9731 var id = this.getId(n);
9732 for(var j = 0; j < fl; j++){
9734 var v = this.ef[j](n);
9736 Roo.log('missing convert for ' + f.name);
9740 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9742 var record = new Record(values, id);
9744 records[i] = record;
9750 totalRecords : totalRecords
9755 * Ext JS Library 1.1.1
9756 * Copyright(c) 2006-2007, Ext JS, LLC.
9758 * Originally Released Under LGPL - original licence link has changed is not relivant.
9761 * <script type="text/javascript">
9765 * @class Roo.data.ArrayReader
9766 * @extends Roo.data.DataReader
9767 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9768 * Each element of that Array represents a row of data fields. The
9769 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9770 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9774 var RecordDef = Roo.data.Record.create([
9775 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9776 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9778 var myReader = new Roo.data.ArrayReader({
9779 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9783 * This would consume an Array like this:
9785 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9787 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9789 * Create a new JsonReader
9790 * @param {Object} meta Metadata configuration options.
9791 * @param {Object} recordType Either an Array of field definition objects
9792 * as specified to {@link Roo.data.Record#create},
9793 * or an {@link Roo.data.Record} object
9794 * created using {@link Roo.data.Record#create}.
9796 Roo.data.ArrayReader = function(meta, recordType){
9797 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9800 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9802 * Create a data block containing Roo.data.Records from an XML document.
9803 * @param {Object} o An Array of row objects which represents the dataset.
9804 * @return {Object} data A data block which is used by an Roo.data.Store object as
9805 * a cache of Roo.data.Records.
9807 readRecords : function(o){
9808 var sid = this.meta ? this.meta.id : null;
9809 var recordType = this.recordType, fields = recordType.prototype.fields;
9812 for(var i = 0; i < root.length; i++){
9815 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9816 for(var j = 0, jlen = fields.length; j < jlen; j++){
9817 var f = fields.items[j];
9818 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9819 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9823 var record = new recordType(values, id);
9825 records[records.length] = record;
9829 totalRecords : records.length
9838 * @class Roo.bootstrap.ComboBox
9839 * @extends Roo.bootstrap.TriggerField
9840 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9841 * @cfg {Boolean} append (true|false) default false
9842 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9843 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9844 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9846 * Create a new ComboBox.
9847 * @param {Object} config Configuration options
9849 Roo.bootstrap.ComboBox = function(config){
9850 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9854 * Fires when the dropdown list is expanded
9855 * @param {Roo.bootstrap.ComboBox} combo This combo box
9860 * Fires when the dropdown list is collapsed
9861 * @param {Roo.bootstrap.ComboBox} combo This combo box
9865 * @event beforeselect
9866 * Fires before a list item is selected. Return false to cancel the selection.
9867 * @param {Roo.bootstrap.ComboBox} combo This combo box
9868 * @param {Roo.data.Record} record The data record returned from the underlying store
9869 * @param {Number} index The index of the selected item in the dropdown list
9871 'beforeselect' : true,
9874 * Fires when a list item is selected
9875 * @param {Roo.bootstrap.ComboBox} combo This combo box
9876 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9877 * @param {Number} index The index of the selected item in the dropdown list
9881 * @event beforequery
9882 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9883 * The event object passed has these properties:
9884 * @param {Roo.bootstrap.ComboBox} combo This combo box
9885 * @param {String} query The query
9886 * @param {Boolean} forceAll true to force "all" query
9887 * @param {Boolean} cancel true to cancel the query
9888 * @param {Object} e The query event object
9890 'beforequery': true,
9893 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9894 * @param {Roo.bootstrap.ComboBox} combo This combo box
9899 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9900 * @param {Roo.bootstrap.ComboBox} combo This combo box
9901 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9906 * Fires when the remove value from the combobox array
9907 * @param {Roo.bootstrap.ComboBox} combo This combo box
9914 this.tickItems = [];
9916 this.selectedIndex = -1;
9917 if(this.mode == 'local'){
9918 if(config.queryDelay === undefined){
9919 this.queryDelay = 10;
9921 if(config.minChars === undefined){
9927 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9930 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9931 * rendering into an Roo.Editor, defaults to false)
9934 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9935 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9938 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9941 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9942 * the dropdown list (defaults to undefined, with no header element)
9946 * @cfg {String/Roo.Template} tpl The template to use to render the output
9950 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9952 listWidth: undefined,
9954 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9955 * mode = 'remote' or 'text' if mode = 'local')
9957 displayField: undefined,
9959 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9960 * mode = 'remote' or 'value' if mode = 'local').
9961 * Note: use of a valueField requires the user make a selection
9962 * in order for a value to be mapped.
9964 valueField: undefined,
9968 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9969 * field's data value (defaults to the underlying DOM element's name)
9971 hiddenName: undefined,
9973 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9977 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9979 selectedClass: 'active',
9982 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9986 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9987 * anchor positions (defaults to 'tl-bl')
9989 listAlign: 'tl-bl?',
9991 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9995 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9996 * query specified by the allQuery config option (defaults to 'query')
9998 triggerAction: 'query',
10000 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10001 * (defaults to 4, does not apply if editable = false)
10005 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10006 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10010 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10011 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10015 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10016 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10020 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10021 * when editable = true (defaults to false)
10023 selectOnFocus:false,
10025 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10027 queryParam: 'query',
10029 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10030 * when mode = 'remote' (defaults to 'Loading...')
10032 loadingText: 'Loading...',
10034 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10038 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10042 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10043 * traditional select (defaults to true)
10047 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10051 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10055 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10056 * listWidth has a higher value)
10060 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10061 * allow the user to set arbitrary text into the field (defaults to false)
10063 forceSelection:false,
10065 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10066 * if typeAhead = true (defaults to 250)
10068 typeAheadDelay : 250,
10070 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10071 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10073 valueNotFoundText : undefined,
10075 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10077 blockFocus : false,
10080 * @cfg {Boolean} disableClear Disable showing of clear button.
10082 disableClear : false,
10084 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10086 alwaysQuery : false,
10089 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10103 btnPosition : 'right',
10105 // element that contains real text value.. (when hidden is used..)
10107 getAutoCreate : function()
10114 if(!this.tickable){
10115 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10120 * ComboBox with tickable selections
10123 var align = this.labelAlign || this.parentLabelAlign();
10126 cls : 'form-group roo-combobox-tickable' //input-group
10132 cls : 'tickable-buttons',
10137 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10144 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10151 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10158 Roo.each(buttons.cn, function(c){
10160 c.cls += ' btn-' + _this.size;
10163 if (_this.disabled) {
10174 cls: 'form-hidden-field'
10178 cls: 'select2-choices',
10182 cls: 'select2-search-field',
10194 cls: 'select2-container input-group select2-container-multi',
10199 cls: 'typeahead typeahead-long dropdown-menu',
10200 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10205 if (align ==='left' && this.fieldLabel.length) {
10207 Roo.log("left and has label");
10213 cls : 'control-label col-sm-' + this.labelWidth,
10214 html : this.fieldLabel
10218 cls : "col-sm-" + (12 - this.labelWidth),
10225 } else if ( this.fieldLabel.length) {
10231 //cls : 'input-group-addon',
10232 html : this.fieldLabel
10242 Roo.log(" no label && no align");
10249 ['xs','sm','md','lg'].map(function(size){
10250 if (settings[size]) {
10251 cfg.cls += ' col-' + size + '-' + settings[size];
10260 initEvents: function()
10264 throw "can not find store for combo";
10266 this.store = Roo.factory(this.store, Roo.data);
10269 this.initTickableEvnets();
10273 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10276 if(this.hiddenName){
10278 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10280 this.hiddenField.dom.value =
10281 this.hiddenValue !== undefined ? this.hiddenValue :
10282 this.value !== undefined ? this.value : '';
10284 // prevent input submission
10285 this.el.dom.removeAttribute('name');
10286 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10291 // this.el.dom.setAttribute('autocomplete', 'off');
10294 var cls = 'x-combo-list';
10295 this.list = this.el.select('ul.dropdown-menu',true).first();
10297 //this.list = new Roo.Layer({
10298 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10304 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10305 _this.list.setWidth(lw);
10308 this.list.on('mouseover', this.onViewOver, this);
10309 this.list.on('mousemove', this.onViewMove, this);
10311 this.list.on('scroll', this.onViewScroll, this);
10314 this.list.swallowEvent('mousewheel');
10315 this.assetHeight = 0;
10318 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10319 this.assetHeight += this.header.getHeight();
10322 this.innerList = this.list.createChild({cls:cls+'-inner'});
10323 this.innerList.on('mouseover', this.onViewOver, this);
10324 this.innerList.on('mousemove', this.onViewMove, this);
10325 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10327 if(this.allowBlank && !this.pageSize && !this.disableClear){
10328 this.footer = this.list.createChild({cls:cls+'-ft'});
10329 this.pageTb = new Roo.Toolbar(this.footer);
10333 this.footer = this.list.createChild({cls:cls+'-ft'});
10334 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10335 {pageSize: this.pageSize});
10339 if (this.pageTb && this.allowBlank && !this.disableClear) {
10341 this.pageTb.add(new Roo.Toolbar.Fill(), {
10342 cls: 'x-btn-icon x-btn-clear',
10344 handler: function()
10347 _this.clearValue();
10348 _this.onSelect(false, -1);
10353 this.assetHeight += this.footer.getHeight();
10358 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10361 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10362 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10364 //this.view.wrapEl.setDisplayed(false);
10365 this.view.on('click', this.onViewClick, this);
10369 this.store.on('beforeload', this.onBeforeLoad, this);
10370 this.store.on('load', this.onLoad, this);
10371 this.store.on('loadexception', this.onLoadException, this);
10373 if(this.resizable){
10374 this.resizer = new Roo.Resizable(this.list, {
10375 pinned:true, handles:'se'
10377 this.resizer.on('resize', function(r, w, h){
10378 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10379 this.listWidth = w;
10380 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10381 this.restrictHeight();
10383 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10386 if(!this.editable){
10387 this.editable = true;
10388 this.setEditable(false);
10393 if (typeof(this.events.add.listeners) != 'undefined') {
10395 this.addicon = this.wrap.createChild(
10396 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10398 this.addicon.on('click', function(e) {
10399 this.fireEvent('add', this);
10402 if (typeof(this.events.edit.listeners) != 'undefined') {
10404 this.editicon = this.wrap.createChild(
10405 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10406 if (this.addicon) {
10407 this.editicon.setStyle('margin-left', '40px');
10409 this.editicon.on('click', function(e) {
10411 // we fire even if inothing is selected..
10412 this.fireEvent('edit', this, this.lastData );
10418 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10419 "up" : function(e){
10420 this.inKeyMode = true;
10424 "down" : function(e){
10425 if(!this.isExpanded()){
10426 this.onTriggerClick();
10428 this.inKeyMode = true;
10433 "enter" : function(e){
10434 // this.onViewClick();
10438 if(this.fireEvent("specialkey", this, e)){
10439 this.onViewClick(false);
10445 "esc" : function(e){
10449 "tab" : function(e){
10452 if(this.fireEvent("specialkey", this, e)){
10453 this.onViewClick(false);
10461 doRelay : function(foo, bar, hname){
10462 if(hname == 'down' || this.scope.isExpanded()){
10463 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10472 this.queryDelay = Math.max(this.queryDelay || 10,
10473 this.mode == 'local' ? 10 : 250);
10476 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10478 if(this.typeAhead){
10479 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10481 if(this.editable !== false){
10482 this.inputEl().on("keyup", this.onKeyUp, this);
10484 if(this.forceSelection){
10485 this.inputEl().on('blur', this.doForce, this);
10489 this.choices = this.el.select('ul.select2-choices', true).first();
10490 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10494 initTickableEvnets: function()
10496 if(this.hiddenName){
10498 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10500 this.hiddenField.dom.value =
10501 this.hiddenValue !== undefined ? this.hiddenValue :
10502 this.value !== undefined ? this.value : '';
10504 // prevent input submission
10505 this.el.dom.removeAttribute('name');
10506 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10511 this.list = this.el.select('ul.dropdown-menu',true).first();
10513 this.choices = this.el.select('ul.select2-choices', true).first();
10514 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10516 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10517 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10519 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10520 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10522 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10523 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10525 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10526 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10527 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10530 this.cancelBtn.hide();
10535 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10536 _this.list.setWidth(lw);
10539 this.list.on('mouseover', this.onViewOver, this);
10540 this.list.on('mousemove', this.onViewMove, this);
10542 this.list.on('scroll', this.onViewScroll, this);
10545 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10548 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10549 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10552 //this.view.wrapEl.setDisplayed(false);
10553 this.view.on('click', this.onViewClick, this);
10557 this.store.on('beforeload', this.onBeforeLoad, this);
10558 this.store.on('load', this.onLoad, this);
10559 this.store.on('loadexception', this.onLoadException, this);
10561 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10562 // "up" : function(e){
10563 // this.inKeyMode = true;
10564 // this.selectPrev();
10567 // "down" : function(e){
10568 // if(!this.isExpanded()){
10569 // this.onTriggerClick();
10571 // this.inKeyMode = true;
10572 // this.selectNext();
10576 // "enter" : function(e){
10577 //// this.onViewClick();
10579 // this.collapse();
10581 // if(this.fireEvent("specialkey", this, e)){
10582 // this.onViewClick(false);
10588 // "esc" : function(e){
10589 // this.collapse();
10592 // "tab" : function(e){
10593 // this.collapse();
10595 // if(this.fireEvent("specialkey", this, e)){
10596 // this.onViewClick(false);
10604 // doRelay : function(foo, bar, hname){
10605 // if(hname == 'down' || this.scope.isExpanded()){
10606 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10611 // forceKeyDown: true
10615 this.queryDelay = Math.max(this.queryDelay || 10,
10616 this.mode == 'local' ? 10 : 250);
10619 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10621 if(this.typeAhead){
10622 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10626 onDestroy : function(){
10628 this.view.setStore(null);
10629 this.view.el.removeAllListeners();
10630 this.view.el.remove();
10631 this.view.purgeListeners();
10634 this.list.dom.innerHTML = '';
10638 this.store.un('beforeload', this.onBeforeLoad, this);
10639 this.store.un('load', this.onLoad, this);
10640 this.store.un('loadexception', this.onLoadException, this);
10642 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10646 fireKey : function(e){
10647 if(e.isNavKeyPress() && !this.list.isVisible()){
10648 this.fireEvent("specialkey", this, e);
10653 onResize: function(w, h){
10654 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10656 // if(typeof w != 'number'){
10657 // // we do not handle it!?!?
10660 // var tw = this.trigger.getWidth();
10661 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10662 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10664 // this.inputEl().setWidth( this.adjustWidth('input', x));
10666 // //this.trigger.setStyle('left', x+'px');
10668 // if(this.list && this.listWidth === undefined){
10669 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10670 // this.list.setWidth(lw);
10671 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10679 * Allow or prevent the user from directly editing the field text. If false is passed,
10680 * the user will only be able to select from the items defined in the dropdown list. This method
10681 * is the runtime equivalent of setting the 'editable' config option at config time.
10682 * @param {Boolean} value True to allow the user to directly edit the field text
10684 setEditable : function(value){
10685 if(value == this.editable){
10688 this.editable = value;
10690 this.inputEl().dom.setAttribute('readOnly', true);
10691 this.inputEl().on('mousedown', this.onTriggerClick, this);
10692 this.inputEl().addClass('x-combo-noedit');
10694 this.inputEl().dom.setAttribute('readOnly', false);
10695 this.inputEl().un('mousedown', this.onTriggerClick, this);
10696 this.inputEl().removeClass('x-combo-noedit');
10702 onBeforeLoad : function(combo,opts){
10703 if(!this.hasFocus){
10707 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10709 this.restrictHeight();
10710 this.selectedIndex = -1;
10714 onLoad : function(){
10716 this.hasQuery = false;
10718 if(!this.hasFocus){
10722 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10723 this.loading.hide();
10726 if(this.store.getCount() > 0){
10728 this.restrictHeight();
10729 if(this.lastQuery == this.allQuery){
10730 if(this.editable && !this.tickable){
10731 this.inputEl().dom.select();
10733 if(!this.selectByValue(this.value, true) && this.autoFocus){
10734 this.select(0, true);
10737 if(this.autoFocus){
10740 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10741 this.taTask.delay(this.typeAheadDelay);
10745 this.onEmptyResults();
10751 onLoadException : function()
10753 this.hasQuery = false;
10755 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10756 this.loading.hide();
10760 Roo.log(this.store.reader.jsonData);
10761 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10763 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10769 onTypeAhead : function(){
10770 if(this.store.getCount() > 0){
10771 var r = this.store.getAt(0);
10772 var newValue = r.data[this.displayField];
10773 var len = newValue.length;
10774 var selStart = this.getRawValue().length;
10776 if(selStart != len){
10777 this.setRawValue(newValue);
10778 this.selectText(selStart, newValue.length);
10784 onSelect : function(record, index){
10786 if(this.fireEvent('beforeselect', this, record, index) !== false){
10788 this.setFromData(index > -1 ? record.data : false);
10791 this.fireEvent('select', this, record, index);
10796 * Returns the currently selected field value or empty string if no value is set.
10797 * @return {String} value The selected value
10799 getValue : function(){
10802 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10805 if(this.valueField){
10806 return typeof this.value != 'undefined' ? this.value : '';
10808 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10813 * Clears any text/value currently set in the field
10815 clearValue : function(){
10816 if(this.hiddenField){
10817 this.hiddenField.dom.value = '';
10820 this.setRawValue('');
10821 this.lastSelectionText = '';
10826 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10827 * will be displayed in the field. If the value does not match the data value of an existing item,
10828 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10829 * Otherwise the field will be blank (although the value will still be set).
10830 * @param {String} value The value to match
10832 setValue : function(v){
10839 if(this.valueField){
10840 var r = this.findRecord(this.valueField, v);
10842 text = r.data[this.displayField];
10843 }else if(this.valueNotFoundText !== undefined){
10844 text = this.valueNotFoundText;
10847 this.lastSelectionText = text;
10848 if(this.hiddenField){
10849 this.hiddenField.dom.value = v;
10851 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10855 * @property {Object} the last set data for the element
10860 * Sets the value of the field based on a object which is related to the record format for the store.
10861 * @param {Object} value the value to set as. or false on reset?
10863 setFromData : function(o){
10870 var dv = ''; // display value
10871 var vv = ''; // value value..
10873 if (this.displayField) {
10874 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10876 // this is an error condition!!!
10877 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10880 if(this.valueField){
10881 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10884 if(this.hiddenField){
10885 this.hiddenField.dom.value = vv;
10887 this.lastSelectionText = dv;
10888 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10892 // no hidden field.. - we store the value in 'value', but still display
10893 // display field!!!!
10894 this.lastSelectionText = dv;
10895 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10901 reset : function(){
10902 // overridden so that last data is reset..
10903 this.setValue(this.originalValue);
10904 this.clearInvalid();
10905 this.lastData = false;
10907 this.view.clearSelections();
10911 findRecord : function(prop, value){
10913 if(this.store.getCount() > 0){
10914 this.store.each(function(r){
10915 if(r.data[prop] == value){
10925 getName: function()
10927 // returns hidden if it's set..
10928 if (!this.rendered) {return ''};
10929 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10933 onViewMove : function(e, t){
10934 this.inKeyMode = false;
10938 onViewOver : function(e, t){
10939 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10942 var item = this.view.findItemFromChild(t);
10945 var index = this.view.indexOf(item);
10946 this.select(index, false);
10951 onViewClick : function(view, doFocus, el, e)
10953 var index = this.view.getSelectedIndexes()[0];
10955 var r = this.store.getAt(index);
10959 if(e.getTarget().nodeName.toLowerCase() != 'input'){
10966 Roo.each(this.tickItems, function(v,k){
10968 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10969 _this.tickItems.splice(k, 1);
10979 this.tickItems.push(r.data);
10984 this.onSelect(r, index);
10986 if(doFocus !== false && !this.blockFocus){
10987 this.inputEl().focus();
10992 restrictHeight : function(){
10993 //this.innerList.dom.style.height = '';
10994 //var inner = this.innerList.dom;
10995 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10996 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10997 //this.list.beginUpdate();
10998 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10999 this.list.alignTo(this.inputEl(), this.listAlign);
11000 //this.list.endUpdate();
11004 onEmptyResults : function(){
11009 * Returns true if the dropdown list is expanded, else false.
11011 isExpanded : function(){
11012 return this.list.isVisible();
11016 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11017 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11018 * @param {String} value The data value of the item to select
11019 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11020 * selected item if it is not currently in view (defaults to true)
11021 * @return {Boolean} True if the value matched an item in the list, else false
11023 selectByValue : function(v, scrollIntoView){
11024 if(v !== undefined && v !== null){
11025 var r = this.findRecord(this.valueField || this.displayField, v);
11027 this.select(this.store.indexOf(r), scrollIntoView);
11035 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11036 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11037 * @param {Number} index The zero-based index of the list item to select
11038 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11039 * selected item if it is not currently in view (defaults to true)
11041 select : function(index, scrollIntoView){
11042 this.selectedIndex = index;
11043 this.view.select(index);
11044 if(scrollIntoView !== false){
11045 var el = this.view.getNode(index);
11047 //this.innerList.scrollChildIntoView(el, false);
11054 selectNext : function(){
11055 var ct = this.store.getCount();
11057 if(this.selectedIndex == -1){
11059 }else if(this.selectedIndex < ct-1){
11060 this.select(this.selectedIndex+1);
11066 selectPrev : function(){
11067 var ct = this.store.getCount();
11069 if(this.selectedIndex == -1){
11071 }else if(this.selectedIndex != 0){
11072 this.select(this.selectedIndex-1);
11078 onKeyUp : function(e){
11079 if(this.editable !== false && !e.isSpecialKey()){
11080 this.lastKey = e.getKey();
11081 this.dqTask.delay(this.queryDelay);
11086 validateBlur : function(){
11087 return !this.list || !this.list.isVisible();
11091 initQuery : function(){
11092 this.doQuery(this.getRawValue());
11096 doForce : function(){
11097 if(this.inputEl().dom.value.length > 0){
11098 this.inputEl().dom.value =
11099 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11105 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11106 * query allowing the query action to be canceled if needed.
11107 * @param {String} query The SQL query to execute
11108 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11109 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11110 * saved in the current store (defaults to false)
11112 doQuery : function(q, forceAll){
11114 if(q === undefined || q === null){
11119 forceAll: forceAll,
11123 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11128 forceAll = qe.forceAll;
11129 if(forceAll === true || (q.length >= this.minChars)){
11131 this.hasQuery = true;
11133 if(this.lastQuery != q || this.alwaysQuery){
11134 this.lastQuery = q;
11135 if(this.mode == 'local'){
11136 this.selectedIndex = -1;
11138 this.store.clearFilter();
11140 this.store.filter(this.displayField, q);
11144 this.store.baseParams[this.queryParam] = q;
11146 var options = {params : this.getParams(q)};
11149 options.add = true;
11150 options.params.start = this.page * this.pageSize;
11153 this.store.load(options);
11155 * this code will make the page width larger, at the beginning, the list not align correctly,
11156 * we should expand the list on onLoad
11157 * so command out it
11162 this.selectedIndex = -1;
11167 this.loadNext = false;
11171 getParams : function(q){
11173 //p[this.queryParam] = q;
11177 p.limit = this.pageSize;
11183 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11185 collapse : function(){
11186 if(!this.isExpanded()){
11194 this.cancelBtn.hide();
11195 this.trigger.show();
11198 Roo.get(document).un('mousedown', this.collapseIf, this);
11199 Roo.get(document).un('mousewheel', this.collapseIf, this);
11200 if (!this.editable) {
11201 Roo.get(document).un('keydown', this.listKeyPress, this);
11203 this.fireEvent('collapse', this);
11207 collapseIf : function(e){
11208 var in_combo = e.within(this.el);
11209 var in_list = e.within(this.list);
11211 if (in_combo || in_list) {
11212 //e.stopPropagation();
11217 this.onTickableFooterButtonClick(e, false, false);
11225 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11227 expand : function(){
11229 if(this.isExpanded() || !this.hasFocus){
11233 this.list.alignTo(this.inputEl(), this.listAlign);
11238 this.tickItems = Roo.apply([], this.item);
11241 this.cancelBtn.show();
11242 this.trigger.hide();
11246 Roo.get(document).on('mousedown', this.collapseIf, this);
11247 Roo.get(document).on('mousewheel', this.collapseIf, this);
11248 if (!this.editable) {
11249 Roo.get(document).on('keydown', this.listKeyPress, this);
11252 this.fireEvent('expand', this);
11256 // Implements the default empty TriggerField.onTriggerClick function
11257 onTriggerClick : function()
11259 Roo.log('trigger click');
11266 this.onTickableTriggerClick();
11271 this.loadNext = false;
11273 if(this.isExpanded()){
11275 if (!this.blockFocus) {
11276 this.inputEl().focus();
11280 this.hasFocus = true;
11281 if(this.triggerAction == 'all') {
11282 this.doQuery(this.allQuery, true);
11284 this.doQuery(this.getRawValue());
11286 if (!this.blockFocus) {
11287 this.inputEl().focus();
11292 onTickableTriggerClick : function()
11295 this.loadNext = false;
11296 this.hasFocus = true;
11298 if(this.triggerAction == 'all') {
11299 this.doQuery(this.allQuery, true);
11301 this.doQuery(this.getRawValue());
11305 listKeyPress : function(e)
11307 //Roo.log('listkeypress');
11308 // scroll to first matching element based on key pres..
11309 if (e.isSpecialKey()) {
11312 var k = String.fromCharCode(e.getKey()).toUpperCase();
11315 var csel = this.view.getSelectedNodes();
11316 var cselitem = false;
11318 var ix = this.view.indexOf(csel[0]);
11319 cselitem = this.store.getAt(ix);
11320 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11326 this.store.each(function(v) {
11328 // start at existing selection.
11329 if (cselitem.id == v.id) {
11335 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11336 match = this.store.indexOf(v);
11342 if (match === false) {
11343 return true; // no more action?
11346 this.view.select(match);
11347 var sn = Roo.get(this.view.getSelectedNodes()[0])
11348 //sn.scrollIntoView(sn.dom.parentNode, false);
11351 onViewScroll : function(e, t){
11353 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11357 this.hasQuery = true;
11359 this.loading = this.list.select('.loading', true).first();
11361 if(this.loading === null){
11362 this.list.createChild({
11364 cls: 'loading select2-more-results select2-active',
11365 html: 'Loading more results...'
11368 this.loading = this.list.select('.loading', true).first();
11370 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11372 this.loading.hide();
11375 this.loading.show();
11380 this.loadNext = true;
11382 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11387 addItem : function(o)
11389 var dv = ''; // display value
11391 if (this.displayField) {
11392 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11394 // this is an error condition!!!
11395 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11402 var choice = this.choices.createChild({
11404 cls: 'select2-search-choice',
11413 cls: 'select2-search-choice-close',
11418 }, this.searchField);
11420 var close = choice.select('a.select2-search-choice-close', true).first()
11422 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11430 this.inputEl().dom.value = '';
11434 onRemoveItem : function(e, _self, o)
11436 e.preventDefault();
11437 var index = this.item.indexOf(o.data) * 1;
11440 Roo.log('not this item?!');
11444 this.item.splice(index, 1);
11449 this.fireEvent('remove', this, e);
11453 syncValue : function()
11455 if(!this.item.length){
11462 Roo.each(this.item, function(i){
11463 if(_this.valueField){
11464 value.push(i[_this.valueField]);
11471 this.value = value.join(',');
11473 if(this.hiddenField){
11474 this.hiddenField.dom.value = this.value;
11478 clearItem : function()
11480 if(!this.multiple){
11486 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11493 inputEl: function ()
11496 return this.searchField;
11498 return this.el.select('input.form-control',true).first();
11502 onTickableFooterButtonClick : function(e, btn, el)
11504 e.preventDefault();
11506 if(btn && btn.name == 'cancel'){
11507 this.tickItems = Roo.apply([], this.item);
11516 Roo.each(this.tickItems, function(o){
11527 * @cfg {Boolean} grow
11531 * @cfg {Number} growMin
11535 * @cfg {Number} growMax
11545 * Ext JS Library 1.1.1
11546 * Copyright(c) 2006-2007, Ext JS, LLC.
11548 * Originally Released Under LGPL - original licence link has changed is not relivant.
11551 * <script type="text/javascript">
11556 * @extends Roo.util.Observable
11557 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11558 * This class also supports single and multi selection modes. <br>
11559 * Create a data model bound view:
11561 var store = new Roo.data.Store(...);
11563 var view = new Roo.View({
11565 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11567 singleSelect: true,
11568 selectedClass: "ydataview-selected",
11572 // listen for node click?
11573 view.on("click", function(vw, index, node, e){
11574 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11578 dataModel.load("foobar.xml");
11580 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11582 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11583 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11585 * Note: old style constructor is still suported (container, template, config)
11588 * Create a new View
11589 * @param {Object} config The config object
11592 Roo.View = function(config, depreciated_tpl, depreciated_config){
11594 this.parent = false;
11596 if (typeof(depreciated_tpl) == 'undefined') {
11597 // new way.. - universal constructor.
11598 Roo.apply(this, config);
11599 this.el = Roo.get(this.el);
11602 this.el = Roo.get(config);
11603 this.tpl = depreciated_tpl;
11604 Roo.apply(this, depreciated_config);
11606 this.wrapEl = this.el.wrap().wrap();
11607 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11610 if(typeof(this.tpl) == "string"){
11611 this.tpl = new Roo.Template(this.tpl);
11613 // support xtype ctors..
11614 this.tpl = new Roo.factory(this.tpl, Roo);
11618 this.tpl.compile();
11623 * @event beforeclick
11624 * Fires before a click is processed. Returns false to cancel the default action.
11625 * @param {Roo.View} this
11626 * @param {Number} index The index of the target node
11627 * @param {HTMLElement} node The target node
11628 * @param {Roo.EventObject} e The raw event object
11630 "beforeclick" : true,
11633 * Fires when a template node is clicked.
11634 * @param {Roo.View} this
11635 * @param {Number} index The index of the target node
11636 * @param {HTMLElement} node The target node
11637 * @param {Roo.EventObject} e The raw event object
11642 * Fires when a template node is double clicked.
11643 * @param {Roo.View} this
11644 * @param {Number} index The index of the target node
11645 * @param {HTMLElement} node The target node
11646 * @param {Roo.EventObject} e The raw event object
11650 * @event contextmenu
11651 * Fires when a template node is right clicked.
11652 * @param {Roo.View} this
11653 * @param {Number} index The index of the target node
11654 * @param {HTMLElement} node The target node
11655 * @param {Roo.EventObject} e The raw event object
11657 "contextmenu" : true,
11659 * @event selectionchange
11660 * Fires when the selected nodes change.
11661 * @param {Roo.View} this
11662 * @param {Array} selections Array of the selected nodes
11664 "selectionchange" : true,
11667 * @event beforeselect
11668 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11669 * @param {Roo.View} this
11670 * @param {HTMLElement} node The node to be selected
11671 * @param {Array} selections Array of currently selected nodes
11673 "beforeselect" : true,
11675 * @event preparedata
11676 * Fires on every row to render, to allow you to change the data.
11677 * @param {Roo.View} this
11678 * @param {Object} data to be rendered (change this)
11680 "preparedata" : true
11688 "click": this.onClick,
11689 "dblclick": this.onDblClick,
11690 "contextmenu": this.onContextMenu,
11694 this.selections = [];
11696 this.cmp = new Roo.CompositeElementLite([]);
11698 this.store = Roo.factory(this.store, Roo.data);
11699 this.setStore(this.store, true);
11702 if ( this.footer && this.footer.xtype) {
11704 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11706 this.footer.dataSource = this.store
11707 this.footer.container = fctr;
11708 this.footer = Roo.factory(this.footer, Roo);
11709 fctr.insertFirst(this.el);
11711 // this is a bit insane - as the paging toolbar seems to detach the el..
11712 // dom.parentNode.parentNode.parentNode
11713 // they get detached?
11717 Roo.View.superclass.constructor.call(this);
11722 Roo.extend(Roo.View, Roo.util.Observable, {
11725 * @cfg {Roo.data.Store} store Data store to load data from.
11730 * @cfg {String|Roo.Element} el The container element.
11735 * @cfg {String|Roo.Template} tpl The template used by this View
11739 * @cfg {String} dataName the named area of the template to use as the data area
11740 * Works with domtemplates roo-name="name"
11744 * @cfg {String} selectedClass The css class to add to selected nodes
11746 selectedClass : "x-view-selected",
11748 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11753 * @cfg {String} text to display on mask (default Loading)
11757 * @cfg {Boolean} multiSelect Allow multiple selection
11759 multiSelect : false,
11761 * @cfg {Boolean} singleSelect Allow single selection
11763 singleSelect: false,
11766 * @cfg {Boolean} toggleSelect - selecting
11768 toggleSelect : false,
11771 * @cfg {Boolean} tickable - selecting
11776 * Returns the element this view is bound to.
11777 * @return {Roo.Element}
11779 getEl : function(){
11780 return this.wrapEl;
11786 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11788 refresh : function(){
11789 Roo.log('refresh');
11792 // if we are using something like 'domtemplate', then
11793 // the what gets used is:
11794 // t.applySubtemplate(NAME, data, wrapping data..)
11795 // the outer template then get' applied with
11796 // the store 'extra data'
11797 // and the body get's added to the
11798 // roo-name="data" node?
11799 // <span class='roo-tpl-{name}'></span> ?????
11803 this.clearSelections();
11804 this.el.update("");
11806 var records = this.store.getRange();
11807 if(records.length < 1) {
11809 // is this valid?? = should it render a template??
11811 this.el.update(this.emptyText);
11815 if (this.dataName) {
11816 this.el.update(t.apply(this.store.meta)); //????
11817 el = this.el.child('.roo-tpl-' + this.dataName);
11820 for(var i = 0, len = records.length; i < len; i++){
11821 var data = this.prepareData(records[i].data, i, records[i]);
11822 this.fireEvent("preparedata", this, data, i, records[i]);
11824 var d = Roo.apply({}, data);
11827 Roo.apply(d, {'roo-id' : Roo.id()});
11831 Roo.each(this.parent.item, function(item){
11832 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11835 Roo.apply(d, {'roo-data-checked' : 'checked'});
11839 html[html.length] = Roo.util.Format.trim(
11841 t.applySubtemplate(this.dataName, d, this.store.meta) :
11848 el.update(html.join(""));
11849 this.nodes = el.dom.childNodes;
11850 this.updateIndexes(0);
11855 * Function to override to reformat the data that is sent to
11856 * the template for each node.
11857 * DEPRICATED - use the preparedata event handler.
11858 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11859 * a JSON object for an UpdateManager bound view).
11861 prepareData : function(data, index, record)
11863 this.fireEvent("preparedata", this, data, index, record);
11867 onUpdate : function(ds, record){
11868 Roo.log('on update');
11869 this.clearSelections();
11870 var index = this.store.indexOf(record);
11871 var n = this.nodes[index];
11872 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11873 n.parentNode.removeChild(n);
11874 this.updateIndexes(index, index);
11880 onAdd : function(ds, records, index)
11882 Roo.log(['on Add', ds, records, index] );
11883 this.clearSelections();
11884 if(this.nodes.length == 0){
11888 var n = this.nodes[index];
11889 for(var i = 0, len = records.length; i < len; i++){
11890 var d = this.prepareData(records[i].data, i, records[i]);
11892 this.tpl.insertBefore(n, d);
11895 this.tpl.append(this.el, d);
11898 this.updateIndexes(index);
11901 onRemove : function(ds, record, index){
11902 Roo.log('onRemove');
11903 this.clearSelections();
11904 var el = this.dataName ?
11905 this.el.child('.roo-tpl-' + this.dataName) :
11908 el.dom.removeChild(this.nodes[index]);
11909 this.updateIndexes(index);
11913 * Refresh an individual node.
11914 * @param {Number} index
11916 refreshNode : function(index){
11917 this.onUpdate(this.store, this.store.getAt(index));
11920 updateIndexes : function(startIndex, endIndex){
11921 var ns = this.nodes;
11922 startIndex = startIndex || 0;
11923 endIndex = endIndex || ns.length - 1;
11924 for(var i = startIndex; i <= endIndex; i++){
11925 ns[i].nodeIndex = i;
11930 * Changes the data store this view uses and refresh the view.
11931 * @param {Store} store
11933 setStore : function(store, initial){
11934 if(!initial && this.store){
11935 this.store.un("datachanged", this.refresh);
11936 this.store.un("add", this.onAdd);
11937 this.store.un("remove", this.onRemove);
11938 this.store.un("update", this.onUpdate);
11939 this.store.un("clear", this.refresh);
11940 this.store.un("beforeload", this.onBeforeLoad);
11941 this.store.un("load", this.onLoad);
11942 this.store.un("loadexception", this.onLoad);
11946 store.on("datachanged", this.refresh, this);
11947 store.on("add", this.onAdd, this);
11948 store.on("remove", this.onRemove, this);
11949 store.on("update", this.onUpdate, this);
11950 store.on("clear", this.refresh, this);
11951 store.on("beforeload", this.onBeforeLoad, this);
11952 store.on("load", this.onLoad, this);
11953 store.on("loadexception", this.onLoad, this);
11961 * onbeforeLoad - masks the loading area.
11964 onBeforeLoad : function(store,opts)
11966 Roo.log('onBeforeLoad');
11968 this.el.update("");
11970 this.el.mask(this.mask ? this.mask : "Loading" );
11972 onLoad : function ()
11979 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11980 * @param {HTMLElement} node
11981 * @return {HTMLElement} The template node
11983 findItemFromChild : function(node){
11984 var el = this.dataName ?
11985 this.el.child('.roo-tpl-' + this.dataName,true) :
11988 if(!node || node.parentNode == el){
11991 var p = node.parentNode;
11992 while(p && p != el){
11993 if(p.parentNode == el){
12002 onClick : function(e){
12003 var item = this.findItemFromChild(e.getTarget());
12005 var index = this.indexOf(item);
12006 if(this.onItemClick(item, index, e) !== false){
12007 this.fireEvent("click", this, index, item, e);
12010 this.clearSelections();
12015 onContextMenu : function(e){
12016 var item = this.findItemFromChild(e.getTarget());
12018 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12023 onDblClick : function(e){
12024 var item = this.findItemFromChild(e.getTarget());
12026 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12030 onItemClick : function(item, index, e)
12032 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12035 if (this.toggleSelect) {
12036 var m = this.isSelected(item) ? 'unselect' : 'select';
12039 _t[m](item, true, false);
12042 if(this.multiSelect || this.singleSelect){
12043 if(this.multiSelect && e.shiftKey && this.lastSelection){
12044 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12046 this.select(item, this.multiSelect && e.ctrlKey);
12047 this.lastSelection = item;
12050 if(!this.tickable){
12051 e.preventDefault();
12059 * Get the number of selected nodes.
12062 getSelectionCount : function(){
12063 return this.selections.length;
12067 * Get the currently selected nodes.
12068 * @return {Array} An array of HTMLElements
12070 getSelectedNodes : function(){
12071 return this.selections;
12075 * Get the indexes of the selected nodes.
12078 getSelectedIndexes : function(){
12079 var indexes = [], s = this.selections;
12080 for(var i = 0, len = s.length; i < len; i++){
12081 indexes.push(s[i].nodeIndex);
12087 * Clear all selections
12088 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12090 clearSelections : function(suppressEvent){
12091 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12092 this.cmp.elements = this.selections;
12093 this.cmp.removeClass(this.selectedClass);
12094 this.selections = [];
12095 if(!suppressEvent){
12096 this.fireEvent("selectionchange", this, this.selections);
12102 * Returns true if the passed node is selected
12103 * @param {HTMLElement/Number} node The node or node index
12104 * @return {Boolean}
12106 isSelected : function(node){
12107 var s = this.selections;
12111 node = this.getNode(node);
12112 return s.indexOf(node) !== -1;
12117 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12118 * @param {Boolean} keepExisting (optional) true to keep existing selections
12119 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12121 select : function(nodeInfo, keepExisting, suppressEvent){
12122 if(nodeInfo instanceof Array){
12124 this.clearSelections(true);
12126 for(var i = 0, len = nodeInfo.length; i < len; i++){
12127 this.select(nodeInfo[i], true, true);
12131 var node = this.getNode(nodeInfo);
12132 if(!node || this.isSelected(node)){
12133 return; // already selected.
12136 this.clearSelections(true);
12138 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12139 Roo.fly(node).addClass(this.selectedClass);
12140 this.selections.push(node);
12141 if(!suppressEvent){
12142 this.fireEvent("selectionchange", this, this.selections);
12150 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12151 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12152 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12154 unselect : function(nodeInfo, keepExisting, suppressEvent)
12156 if(nodeInfo instanceof Array){
12157 Roo.each(this.selections, function(s) {
12158 this.unselect(s, nodeInfo);
12162 var node = this.getNode(nodeInfo);
12163 if(!node || !this.isSelected(node)){
12164 Roo.log("not selected");
12165 return; // not selected.
12169 Roo.each(this.selections, function(s) {
12171 Roo.fly(node).removeClass(this.selectedClass);
12178 this.selections= ns;
12179 this.fireEvent("selectionchange", this, this.selections);
12183 * Gets a template node.
12184 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12185 * @return {HTMLElement} The node or null if it wasn't found
12187 getNode : function(nodeInfo){
12188 if(typeof nodeInfo == "string"){
12189 return document.getElementById(nodeInfo);
12190 }else if(typeof nodeInfo == "number"){
12191 return this.nodes[nodeInfo];
12197 * Gets a range template nodes.
12198 * @param {Number} startIndex
12199 * @param {Number} endIndex
12200 * @return {Array} An array of nodes
12202 getNodes : function(start, end){
12203 var ns = this.nodes;
12204 start = start || 0;
12205 end = typeof end == "undefined" ? ns.length - 1 : end;
12208 for(var i = start; i <= end; i++){
12212 for(var i = start; i >= end; i--){
12220 * Finds the index of the passed node
12221 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12222 * @return {Number} The index of the node or -1
12224 indexOf : function(node){
12225 node = this.getNode(node);
12226 if(typeof node.nodeIndex == "number"){
12227 return node.nodeIndex;
12229 var ns = this.nodes;
12230 for(var i = 0, len = ns.length; i < len; i++){
12241 * based on jquery fullcalendar
12245 Roo.bootstrap = Roo.bootstrap || {};
12247 * @class Roo.bootstrap.Calendar
12248 * @extends Roo.bootstrap.Component
12249 * Bootstrap Calendar class
12250 * @cfg {Boolean} loadMask (true|false) default false
12251 * @cfg {Object} header generate the user specific header of the calendar, default false
12254 * Create a new Container
12255 * @param {Object} config The config object
12260 Roo.bootstrap.Calendar = function(config){
12261 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12265 * Fires when a date is selected
12266 * @param {DatePicker} this
12267 * @param {Date} date The selected date
12271 * @event monthchange
12272 * Fires when the displayed month changes
12273 * @param {DatePicker} this
12274 * @param {Date} date The selected month
12276 'monthchange': true,
12278 * @event evententer
12279 * Fires when mouse over an event
12280 * @param {Calendar} this
12281 * @param {event} Event
12283 'evententer': true,
12285 * @event eventleave
12286 * Fires when the mouse leaves an
12287 * @param {Calendar} this
12290 'eventleave': true,
12292 * @event eventclick
12293 * Fires when the mouse click an
12294 * @param {Calendar} this
12303 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12306 * @cfg {Number} startDay
12307 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12315 getAutoCreate : function(){
12318 var fc_button = function(name, corner, style, content ) {
12319 return Roo.apply({},{
12321 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12323 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12326 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12337 style : 'width:100%',
12344 cls : 'fc-header-left',
12346 fc_button('prev', 'left', 'arrow', '‹' ),
12347 fc_button('next', 'right', 'arrow', '›' ),
12348 { tag: 'span', cls: 'fc-header-space' },
12349 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12357 cls : 'fc-header-center',
12361 cls: 'fc-header-title',
12364 html : 'month / year'
12372 cls : 'fc-header-right',
12374 /* fc_button('month', 'left', '', 'month' ),
12375 fc_button('week', '', '', 'week' ),
12376 fc_button('day', 'right', '', 'day' )
12388 header = this.header;
12391 var cal_heads = function() {
12393 // fixme - handle this.
12395 for (var i =0; i < Date.dayNames.length; i++) {
12396 var d = Date.dayNames[i];
12399 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12400 html : d.substring(0,3)
12404 ret[0].cls += ' fc-first';
12405 ret[6].cls += ' fc-last';
12408 var cal_cell = function(n) {
12411 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12416 cls: 'fc-day-number',
12420 cls: 'fc-day-content',
12424 style: 'position: relative;' // height: 17px;
12436 var cal_rows = function() {
12439 for (var r = 0; r < 6; r++) {
12446 for (var i =0; i < Date.dayNames.length; i++) {
12447 var d = Date.dayNames[i];
12448 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12451 row.cn[0].cls+=' fc-first';
12452 row.cn[0].cn[0].style = 'min-height:90px';
12453 row.cn[6].cls+=' fc-last';
12457 ret[0].cls += ' fc-first';
12458 ret[4].cls += ' fc-prev-last';
12459 ret[5].cls += ' fc-last';
12466 cls: 'fc-border-separate',
12467 style : 'width:100%',
12475 cls : 'fc-first fc-last',
12493 cls : 'fc-content',
12494 style : "position: relative;",
12497 cls : 'fc-view fc-view-month fc-grid',
12498 style : 'position: relative',
12499 unselectable : 'on',
12502 cls : 'fc-event-container',
12503 style : 'position:absolute;z-index:8;top:0;left:0;'
12521 initEvents : function()
12524 throw "can not find store for calendar";
12530 style: "text-align:center",
12534 style: "background-color:white;width:50%;margin:250 auto",
12538 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12549 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12551 var size = this.el.select('.fc-content', true).first().getSize();
12552 this.maskEl.setSize(size.width, size.height);
12553 this.maskEl.enableDisplayMode("block");
12554 if(!this.loadMask){
12555 this.maskEl.hide();
12558 this.store = Roo.factory(this.store, Roo.data);
12559 this.store.on('load', this.onLoad, this);
12560 this.store.on('beforeload', this.onBeforeLoad, this);
12564 this.cells = this.el.select('.fc-day',true);
12565 //Roo.log(this.cells);
12566 this.textNodes = this.el.query('.fc-day-number');
12567 this.cells.addClassOnOver('fc-state-hover');
12569 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12570 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12571 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12572 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12574 this.on('monthchange', this.onMonthChange, this);
12576 this.update(new Date().clearTime());
12579 resize : function() {
12580 var sz = this.el.getSize();
12582 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12583 this.el.select('.fc-day-content div',true).setHeight(34);
12588 showPrevMonth : function(e){
12589 this.update(this.activeDate.add("mo", -1));
12591 showToday : function(e){
12592 this.update(new Date().clearTime());
12595 showNextMonth : function(e){
12596 this.update(this.activeDate.add("mo", 1));
12600 showPrevYear : function(){
12601 this.update(this.activeDate.add("y", -1));
12605 showNextYear : function(){
12606 this.update(this.activeDate.add("y", 1));
12611 update : function(date)
12613 var vd = this.activeDate;
12614 this.activeDate = date;
12615 // if(vd && this.el){
12616 // var t = date.getTime();
12617 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12618 // Roo.log('using add remove');
12620 // this.fireEvent('monthchange', this, date);
12622 // this.cells.removeClass("fc-state-highlight");
12623 // this.cells.each(function(c){
12624 // if(c.dateValue == t){
12625 // c.addClass("fc-state-highlight");
12626 // setTimeout(function(){
12627 // try{c.dom.firstChild.focus();}catch(e){}
12637 var days = date.getDaysInMonth();
12639 var firstOfMonth = date.getFirstDateOfMonth();
12640 var startingPos = firstOfMonth.getDay()-this.startDay;
12642 if(startingPos < this.startDay){
12646 var pm = date.add(Date.MONTH, -1);
12647 var prevStart = pm.getDaysInMonth()-startingPos;
12649 this.cells = this.el.select('.fc-day',true);
12650 this.textNodes = this.el.query('.fc-day-number');
12651 this.cells.addClassOnOver('fc-state-hover');
12653 var cells = this.cells.elements;
12654 var textEls = this.textNodes;
12656 Roo.each(cells, function(cell){
12657 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12660 days += startingPos;
12662 // convert everything to numbers so it's fast
12663 var day = 86400000;
12664 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12667 //Roo.log(prevStart);
12669 var today = new Date().clearTime().getTime();
12670 var sel = date.clearTime().getTime();
12671 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12672 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12673 var ddMatch = this.disabledDatesRE;
12674 var ddText = this.disabledDatesText;
12675 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12676 var ddaysText = this.disabledDaysText;
12677 var format = this.format;
12679 var setCellClass = function(cal, cell){
12683 //Roo.log('set Cell Class');
12685 var t = d.getTime();
12689 cell.dateValue = t;
12691 cell.className += " fc-today";
12692 cell.className += " fc-state-highlight";
12693 cell.title = cal.todayText;
12696 // disable highlight in other month..
12697 //cell.className += " fc-state-highlight";
12702 cell.className = " fc-state-disabled";
12703 cell.title = cal.minText;
12707 cell.className = " fc-state-disabled";
12708 cell.title = cal.maxText;
12712 if(ddays.indexOf(d.getDay()) != -1){
12713 cell.title = ddaysText;
12714 cell.className = " fc-state-disabled";
12717 if(ddMatch && format){
12718 var fvalue = d.dateFormat(format);
12719 if(ddMatch.test(fvalue)){
12720 cell.title = ddText.replace("%0", fvalue);
12721 cell.className = " fc-state-disabled";
12725 if (!cell.initialClassName) {
12726 cell.initialClassName = cell.dom.className;
12729 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12734 for(; i < startingPos; i++) {
12735 textEls[i].innerHTML = (++prevStart);
12736 d.setDate(d.getDate()+1);
12738 cells[i].className = "fc-past fc-other-month";
12739 setCellClass(this, cells[i]);
12744 for(; i < days; i++){
12745 intDay = i - startingPos + 1;
12746 textEls[i].innerHTML = (intDay);
12747 d.setDate(d.getDate()+1);
12749 cells[i].className = ''; // "x-date-active";
12750 setCellClass(this, cells[i]);
12754 for(; i < 42; i++) {
12755 textEls[i].innerHTML = (++extraDays);
12756 d.setDate(d.getDate()+1);
12758 cells[i].className = "fc-future fc-other-month";
12759 setCellClass(this, cells[i]);
12762 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12764 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12766 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12767 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12769 if(totalRows != 6){
12770 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12771 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12774 this.fireEvent('monthchange', this, date);
12778 if(!this.internalRender){
12779 var main = this.el.dom.firstChild;
12780 var w = main.offsetWidth;
12781 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12782 Roo.fly(main).setWidth(w);
12783 this.internalRender = true;
12784 // opera does not respect the auto grow header center column
12785 // then, after it gets a width opera refuses to recalculate
12786 // without a second pass
12787 if(Roo.isOpera && !this.secondPass){
12788 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12789 this.secondPass = true;
12790 this.update.defer(10, this, [date]);
12797 findCell : function(dt) {
12798 dt = dt.clearTime().getTime();
12800 this.cells.each(function(c){
12801 //Roo.log("check " +c.dateValue + '?=' + dt);
12802 if(c.dateValue == dt){
12812 findCells : function(ev) {
12813 var s = ev.start.clone().clearTime().getTime();
12815 var e= ev.end.clone().clearTime().getTime();
12818 this.cells.each(function(c){
12819 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12821 if(c.dateValue > e){
12824 if(c.dateValue < s){
12833 // findBestRow: function(cells)
12837 // for (var i =0 ; i < cells.length;i++) {
12838 // ret = Math.max(cells[i].rows || 0,ret);
12845 addItem : function(ev)
12847 // look for vertical location slot in
12848 var cells = this.findCells(ev);
12850 // ev.row = this.findBestRow(cells);
12852 // work out the location.
12856 for(var i =0; i < cells.length; i++) {
12858 cells[i].row = cells[0].row;
12861 cells[i].row = cells[i].row + 1;
12871 if (crow.start.getY() == cells[i].getY()) {
12873 crow.end = cells[i];
12890 cells[0].events.push(ev);
12892 this.calevents.push(ev);
12895 clearEvents: function() {
12897 if(!this.calevents){
12901 Roo.each(this.cells.elements, function(c){
12907 Roo.each(this.calevents, function(e) {
12908 Roo.each(e.els, function(el) {
12909 el.un('mouseenter' ,this.onEventEnter, this);
12910 el.un('mouseleave' ,this.onEventLeave, this);
12915 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12921 renderEvents: function()
12925 this.cells.each(function(c) {
12934 if(c.row != c.events.length){
12935 r = 4 - (4 - (c.row - c.events.length));
12938 c.events = ev.slice(0, r);
12939 c.more = ev.slice(r);
12941 if(c.more.length && c.more.length == 1){
12942 c.events.push(c.more.pop());
12945 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12949 this.cells.each(function(c) {
12951 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12954 for (var e = 0; e < c.events.length; e++){
12955 var ev = c.events[e];
12956 var rows = ev.rows;
12958 for(var i = 0; i < rows.length; i++) {
12960 // how many rows should it span..
12963 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12964 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12966 unselectable : "on",
12969 cls: 'fc-event-inner',
12973 // cls: 'fc-event-time',
12974 // html : cells.length > 1 ? '' : ev.time
12978 cls: 'fc-event-title',
12979 html : String.format('{0}', ev.title)
12986 cls: 'ui-resizable-handle ui-resizable-e',
12987 html : '  '
12994 cfg.cls += ' fc-event-start';
12996 if ((i+1) == rows.length) {
12997 cfg.cls += ' fc-event-end';
13000 var ctr = _this.el.select('.fc-event-container',true).first();
13001 var cg = ctr.createChild(cfg);
13003 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13004 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13006 var r = (c.more.length) ? 1 : 0;
13007 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13008 cg.setWidth(ebox.right - sbox.x -2);
13010 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13011 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13012 cg.on('click', _this.onEventClick, _this, ev);
13023 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13024 style : 'position: absolute',
13025 unselectable : "on",
13028 cls: 'fc-event-inner',
13032 cls: 'fc-event-title',
13040 cls: 'ui-resizable-handle ui-resizable-e',
13041 html : '  '
13047 var ctr = _this.el.select('.fc-event-container',true).first();
13048 var cg = ctr.createChild(cfg);
13050 var sbox = c.select('.fc-day-content',true).first().getBox();
13051 var ebox = c.select('.fc-day-content',true).first().getBox();
13053 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13054 cg.setWidth(ebox.right - sbox.x -2);
13056 cg.on('click', _this.onMoreEventClick, _this, c.more);
13066 onEventEnter: function (e, el,event,d) {
13067 this.fireEvent('evententer', this, el, event);
13070 onEventLeave: function (e, el,event,d) {
13071 this.fireEvent('eventleave', this, el, event);
13074 onEventClick: function (e, el,event,d) {
13075 this.fireEvent('eventclick', this, el, event);
13078 onMonthChange: function () {
13082 onMoreEventClick: function(e, el, more)
13086 this.calpopover.placement = 'right';
13087 this.calpopover.setTitle('More');
13089 this.calpopover.setContent('');
13091 var ctr = this.calpopover.el.select('.popover-content', true).first();
13093 Roo.each(more, function(m){
13095 cls : 'fc-event-hori fc-event-draggable',
13098 var cg = ctr.createChild(cfg);
13100 cg.on('click', _this.onEventClick, _this, m);
13103 this.calpopover.show(el);
13108 onLoad: function ()
13110 this.calevents = [];
13113 if(this.store.getCount() > 0){
13114 this.store.data.each(function(d){
13117 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13118 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13119 time : d.data.start_time,
13120 title : d.data.title,
13121 description : d.data.description,
13122 venue : d.data.venue
13127 this.renderEvents();
13129 if(this.calevents.length && this.loadMask){
13130 this.maskEl.hide();
13134 onBeforeLoad: function()
13136 this.clearEvents();
13138 this.maskEl.show();
13152 * @class Roo.bootstrap.Popover
13153 * @extends Roo.bootstrap.Component
13154 * Bootstrap Popover class
13155 * @cfg {String} html contents of the popover (or false to use children..)
13156 * @cfg {String} title of popover (or false to hide)
13157 * @cfg {String} placement how it is placed
13158 * @cfg {String} trigger click || hover (or false to trigger manually)
13159 * @cfg {String} over what (parent or false to trigger manually.)
13162 * Create a new Popover
13163 * @param {Object} config The config object
13166 Roo.bootstrap.Popover = function(config){
13167 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13170 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13172 title: 'Fill in a title',
13175 placement : 'right',
13176 trigger : 'hover', // hover
13180 can_build_overlaid : false,
13182 getChildContainer : function()
13184 return this.el.select('.popover-content',true).first();
13187 getAutoCreate : function(){
13188 Roo.log('make popover?');
13190 cls : 'popover roo-dynamic',
13191 style: 'display:block',
13197 cls : 'popover-inner',
13201 cls: 'popover-title',
13205 cls : 'popover-content',
13216 setTitle: function(str)
13218 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13220 setContent: function(str)
13222 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13224 // as it get's added to the bottom of the page.
13225 onRender : function(ct, position)
13227 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13229 var cfg = Roo.apply({}, this.getAutoCreate());
13233 cfg.cls += ' ' + this.cls;
13236 cfg.style = this.style;
13238 Roo.log("adding to ")
13239 this.el = Roo.get(document.body).createChild(cfg, position);
13245 initEvents : function()
13247 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13248 this.el.enableDisplayMode('block');
13250 if (this.over === false) {
13253 if (this.triggers === false) {
13256 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13257 var triggers = this.trigger ? this.trigger.split(' ') : [];
13258 Roo.each(triggers, function(trigger) {
13260 if (trigger == 'click') {
13261 on_el.on('click', this.toggle, this);
13262 } else if (trigger != 'manual') {
13263 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13264 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13266 on_el.on(eventIn ,this.enter, this);
13267 on_el.on(eventOut, this.leave, this);
13278 toggle : function () {
13279 this.hoverState == 'in' ? this.leave() : this.enter();
13282 enter : function () {
13285 clearTimeout(this.timeout);
13287 this.hoverState = 'in'
13289 if (!this.delay || !this.delay.show) {
13294 this.timeout = setTimeout(function () {
13295 if (_t.hoverState == 'in') {
13298 }, this.delay.show)
13300 leave : function() {
13301 clearTimeout(this.timeout);
13303 this.hoverState = 'out'
13305 if (!this.delay || !this.delay.hide) {
13310 this.timeout = setTimeout(function () {
13311 if (_t.hoverState == 'out') {
13314 }, this.delay.hide)
13317 show : function (on_el)
13320 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13323 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13324 if (this.html !== false) {
13325 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13327 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13328 if (!this.title.length) {
13329 this.el.select('.popover-title',true).hide();
13332 var placement = typeof this.placement == 'function' ?
13333 this.placement.call(this, this.el, on_el) :
13336 var autoToken = /\s?auto?\s?/i;
13337 var autoPlace = autoToken.test(placement);
13339 placement = placement.replace(autoToken, '') || 'top';
13343 //this.el.setXY([0,0]);
13345 this.el.dom.style.display='block';
13346 this.el.addClass(placement);
13348 //this.el.appendTo(on_el);
13350 var p = this.getPosition();
13351 var box = this.el.getBox();
13356 var align = Roo.bootstrap.Popover.alignment[placement]
13357 this.el.alignTo(on_el, align[0],align[1]);
13358 //var arrow = this.el.select('.arrow',true).first();
13359 //arrow.set(align[2],
13361 this.el.addClass('in');
13362 this.hoverState = null;
13364 if (this.el.hasClass('fade')) {
13371 this.el.setXY([0,0]);
13372 this.el.removeClass('in');
13379 Roo.bootstrap.Popover.alignment = {
13380 'left' : ['r-l', [-10,0], 'right'],
13381 'right' : ['l-r', [10,0], 'left'],
13382 'bottom' : ['t-b', [0,10], 'top'],
13383 'top' : [ 'b-t', [0,-10], 'bottom']
13394 * @class Roo.bootstrap.Progress
13395 * @extends Roo.bootstrap.Component
13396 * Bootstrap Progress class
13397 * @cfg {Boolean} striped striped of the progress bar
13398 * @cfg {Boolean} active animated of the progress bar
13402 * Create a new Progress
13403 * @param {Object} config The config object
13406 Roo.bootstrap.Progress = function(config){
13407 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13410 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13415 getAutoCreate : function(){
13423 cfg.cls += ' progress-striped';
13427 cfg.cls += ' active';
13446 * @class Roo.bootstrap.ProgressBar
13447 * @extends Roo.bootstrap.Component
13448 * Bootstrap ProgressBar class
13449 * @cfg {Number} aria_valuenow aria-value now
13450 * @cfg {Number} aria_valuemin aria-value min
13451 * @cfg {Number} aria_valuemax aria-value max
13452 * @cfg {String} label label for the progress bar
13453 * @cfg {String} panel (success | info | warning | danger )
13454 * @cfg {String} role role of the progress bar
13455 * @cfg {String} sr_only text
13459 * Create a new ProgressBar
13460 * @param {Object} config The config object
13463 Roo.bootstrap.ProgressBar = function(config){
13464 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13467 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13471 aria_valuemax : 100,
13477 getAutoCreate : function()
13482 cls: 'progress-bar',
13483 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13495 cfg.role = this.role;
13498 if(this.aria_valuenow){
13499 cfg['aria-valuenow'] = this.aria_valuenow;
13502 if(this.aria_valuemin){
13503 cfg['aria-valuemin'] = this.aria_valuemin;
13506 if(this.aria_valuemax){
13507 cfg['aria-valuemax'] = this.aria_valuemax;
13510 if(this.label && !this.sr_only){
13511 cfg.html = this.label;
13515 cfg.cls += ' progress-bar-' + this.panel;
13521 update : function(aria_valuenow)
13523 this.aria_valuenow = aria_valuenow;
13525 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13540 * @class Roo.bootstrap.TabPanel
13541 * @extends Roo.bootstrap.Component
13542 * Bootstrap TabPanel class
13543 * @cfg {Boolean} active panel active
13544 * @cfg {String} html panel content
13545 * @cfg {String} tabId tab relate id
13546 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13550 * Create a new TabPanel
13551 * @param {Object} config The config object
13554 Roo.bootstrap.TabPanel = function(config){
13555 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13559 * Fires when the active status changes
13560 * @param {Roo.bootstrap.TabPanel} this
13561 * @param {Boolean} state the new state
13568 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13575 getAutoCreate : function(){
13579 html: this.html || ''
13583 cfg.cls += ' active';
13587 cfg.tabId = this.tabId;
13592 onRender : function(ct, position)
13594 // Roo.log("Call onRender: " + this.xtype);
13596 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13598 if (this.navId && this.tabId) {
13599 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13601 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13603 item.on('changed', function(item, state) {
13604 this.setActive(state);
13610 setActive: function(state)
13612 Roo.log("panel - set active " + this.tabId + "=" + state);
13614 this.active = state;
13616 this.el.removeClass('active');
13618 } else if (!this.el.hasClass('active')) {
13619 this.el.addClass('active');
13621 this.fireEvent('changed', this, state);
13638 * @class Roo.bootstrap.DateField
13639 * @extends Roo.bootstrap.Input
13640 * Bootstrap DateField class
13641 * @cfg {Number} weekStart default 0
13642 * @cfg {Number} weekStart default 0
13643 * @cfg {Number} viewMode default empty, (months|years)
13644 * @cfg {Number} minViewMode default empty, (months|years)
13645 * @cfg {Number} startDate default -Infinity
13646 * @cfg {Number} endDate default Infinity
13647 * @cfg {Boolean} todayHighlight default false
13648 * @cfg {Boolean} todayBtn default false
13649 * @cfg {Boolean} calendarWeeks default false
13650 * @cfg {Object} daysOfWeekDisabled default empty
13652 * @cfg {Boolean} keyboardNavigation default true
13653 * @cfg {String} language default en
13656 * Create a new DateField
13657 * @param {Object} config The config object
13660 Roo.bootstrap.DateField = function(config){
13661 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13665 * Fires when this field show.
13666 * @param {Roo.bootstrap.DateField} this
13667 * @param {Mixed} date The date value
13672 * Fires when this field hide.
13673 * @param {Roo.bootstrap.DateField} this
13674 * @param {Mixed} date The date value
13679 * Fires when select a date.
13680 * @param {Roo.bootstrap.DateField} this
13681 * @param {Mixed} date The date value
13687 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13690 * @cfg {String} format
13691 * The default date format string which can be overriden for localization support. The format must be
13692 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13696 * @cfg {String} altFormats
13697 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13698 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13700 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13708 todayHighlight : false,
13714 keyboardNavigation: true,
13716 calendarWeeks: false,
13718 startDate: -Infinity,
13722 daysOfWeekDisabled: [],
13726 UTCDate: function()
13728 return new Date(Date.UTC.apply(Date, arguments));
13731 UTCToday: function()
13733 var today = new Date();
13734 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13737 getDate: function() {
13738 var d = this.getUTCDate();
13739 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13742 getUTCDate: function() {
13746 setDate: function(d) {
13747 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13750 setUTCDate: function(d) {
13752 this.setValue(this.formatDate(this.date));
13755 onRender: function(ct, position)
13758 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13760 this.language = this.language || 'en';
13761 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13762 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13764 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13765 this.format = this.format || 'm/d/y';
13766 this.isInline = false;
13767 this.isInput = true;
13768 this.component = this.el.select('.add-on', true).first() || false;
13769 this.component = (this.component && this.component.length === 0) ? false : this.component;
13770 this.hasInput = this.component && this.inputEL().length;
13772 if (typeof(this.minViewMode === 'string')) {
13773 switch (this.minViewMode) {
13775 this.minViewMode = 1;
13778 this.minViewMode = 2;
13781 this.minViewMode = 0;
13786 if (typeof(this.viewMode === 'string')) {
13787 switch (this.viewMode) {
13800 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13802 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13804 this.picker().on('mousedown', this.onMousedown, this);
13805 this.picker().on('click', this.onClick, this);
13807 this.picker().addClass('datepicker-dropdown');
13809 this.startViewMode = this.viewMode;
13812 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13813 if(!this.calendarWeeks){
13818 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13819 v.attr('colspan', function(i, val){
13820 return parseInt(val) + 1;
13825 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13827 this.setStartDate(this.startDate);
13828 this.setEndDate(this.endDate);
13830 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13837 if(this.isInline) {
13842 picker : function()
13844 return this.el.select('.datepicker', true).first();
13847 fillDow: function()
13849 var dowCnt = this.weekStart;
13858 if(this.calendarWeeks){
13866 while (dowCnt < this.weekStart + 7) {
13870 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13874 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13877 fillMonths: function()
13880 var months = this.picker().select('>.datepicker-months td', true).first();
13882 months.dom.innerHTML = '';
13888 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13891 months.createChild(month);
13899 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13901 if (this.date < this.startDate) {
13902 this.viewDate = new Date(this.startDate);
13903 } else if (this.date > this.endDate) {
13904 this.viewDate = new Date(this.endDate);
13906 this.viewDate = new Date(this.date);
13914 var d = new Date(this.viewDate),
13915 year = d.getUTCFullYear(),
13916 month = d.getUTCMonth(),
13917 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13918 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13919 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13920 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13921 currentDate = this.date && this.date.valueOf(),
13922 today = this.UTCToday();
13924 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13926 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13928 // this.picker.select('>tfoot th.today').
13929 // .text(dates[this.language].today)
13930 // .toggle(this.todayBtn !== false);
13932 this.updateNavArrows();
13935 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13937 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13939 prevMonth.setUTCDate(day);
13941 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13943 var nextMonth = new Date(prevMonth);
13945 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13947 nextMonth = nextMonth.valueOf();
13949 var fillMonths = false;
13951 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13953 while(prevMonth.valueOf() < nextMonth) {
13956 if (prevMonth.getUTCDay() === this.weekStart) {
13958 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13966 if(this.calendarWeeks){
13967 // ISO 8601: First week contains first thursday.
13968 // ISO also states week starts on Monday, but we can be more abstract here.
13970 // Start of current week: based on weekstart/current date
13971 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13972 // Thursday of this week
13973 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13974 // First Thursday of year, year from thursday
13975 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13976 // Calendar week: ms between thursdays, div ms per day, div 7 days
13977 calWeek = (th - yth) / 864e5 / 7 + 1;
13979 fillMonths.cn.push({
13987 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13989 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13992 if (this.todayHighlight &&
13993 prevMonth.getUTCFullYear() == today.getFullYear() &&
13994 prevMonth.getUTCMonth() == today.getMonth() &&
13995 prevMonth.getUTCDate() == today.getDate()) {
13996 clsName += ' today';
13999 if (currentDate && prevMonth.valueOf() === currentDate) {
14000 clsName += ' active';
14003 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14004 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14005 clsName += ' disabled';
14008 fillMonths.cn.push({
14010 cls: 'day ' + clsName,
14011 html: prevMonth.getDate()
14014 prevMonth.setDate(prevMonth.getDate()+1);
14017 var currentYear = this.date && this.date.getUTCFullYear();
14018 var currentMonth = this.date && this.date.getUTCMonth();
14020 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14022 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14023 v.removeClass('active');
14025 if(currentYear === year && k === currentMonth){
14026 v.addClass('active');
14029 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14030 v.addClass('disabled');
14036 year = parseInt(year/10, 10) * 10;
14038 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14040 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14043 for (var i = -1; i < 11; i++) {
14044 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14046 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14054 showMode: function(dir)
14057 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14059 Roo.each(this.picker().select('>div',true).elements, function(v){
14060 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14063 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14068 if(this.isInline) return;
14070 this.picker().removeClass(['bottom', 'top']);
14072 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14074 * place to the top of element!
14078 this.picker().addClass('top');
14079 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14084 this.picker().addClass('bottom');
14086 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14089 parseDate : function(value)
14091 if(!value || value instanceof Date){
14094 var v = Date.parseDate(value, this.format);
14095 if (!v && this.useIso) {
14096 v = Date.parseDate(value, 'Y-m-d');
14098 if(!v && this.altFormats){
14099 if(!this.altFormatsArray){
14100 this.altFormatsArray = this.altFormats.split("|");
14102 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14103 v = Date.parseDate(value, this.altFormatsArray[i]);
14109 formatDate : function(date, fmt)
14111 return (!date || !(date instanceof Date)) ?
14112 date : date.dateFormat(fmt || this.format);
14115 onFocus : function()
14117 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14121 onBlur : function()
14123 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14125 var d = this.inputEl().getValue();
14136 this.picker().show();
14140 this.fireEvent('show', this, this.date);
14145 if(this.isInline) return;
14146 this.picker().hide();
14147 this.viewMode = this.startViewMode;
14150 this.fireEvent('hide', this, this.date);
14154 onMousedown: function(e)
14156 e.stopPropagation();
14157 e.preventDefault();
14162 Roo.bootstrap.DateField.superclass.keyup.call(this);
14166 setValue: function(v)
14168 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14170 var d = new Date(v);
14172 if(isNaN(d.getTime())){
14176 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14180 this.fireEvent('select', this, this.date);
14184 getValue: function()
14186 return this.formatDate(this.date);
14189 fireKey: function(e)
14191 if (!this.picker().isVisible()){
14192 if (e.keyCode == 27) // allow escape to hide and re-show picker
14196 var dateChanged = false,
14198 newDate, newViewDate;
14203 e.preventDefault();
14207 if (!this.keyboardNavigation) break;
14208 dir = e.keyCode == 37 ? -1 : 1;
14211 newDate = this.moveYear(this.date, dir);
14212 newViewDate = this.moveYear(this.viewDate, dir);
14213 } else if (e.shiftKey){
14214 newDate = this.moveMonth(this.date, dir);
14215 newViewDate = this.moveMonth(this.viewDate, dir);
14217 newDate = new Date(this.date);
14218 newDate.setUTCDate(this.date.getUTCDate() + dir);
14219 newViewDate = new Date(this.viewDate);
14220 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14222 if (this.dateWithinRange(newDate)){
14223 this.date = newDate;
14224 this.viewDate = newViewDate;
14225 this.setValue(this.formatDate(this.date));
14227 e.preventDefault();
14228 dateChanged = true;
14233 if (!this.keyboardNavigation) break;
14234 dir = e.keyCode == 38 ? -1 : 1;
14236 newDate = this.moveYear(this.date, dir);
14237 newViewDate = this.moveYear(this.viewDate, dir);
14238 } else if (e.shiftKey){
14239 newDate = this.moveMonth(this.date, dir);
14240 newViewDate = this.moveMonth(this.viewDate, dir);
14242 newDate = new Date(this.date);
14243 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14244 newViewDate = new Date(this.viewDate);
14245 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14247 if (this.dateWithinRange(newDate)){
14248 this.date = newDate;
14249 this.viewDate = newViewDate;
14250 this.setValue(this.formatDate(this.date));
14252 e.preventDefault();
14253 dateChanged = true;
14257 this.setValue(this.formatDate(this.date));
14259 e.preventDefault();
14262 this.setValue(this.formatDate(this.date));
14270 onClick: function(e)
14272 e.stopPropagation();
14273 e.preventDefault();
14275 var target = e.getTarget();
14277 if(target.nodeName.toLowerCase() === 'i'){
14278 target = Roo.get(target).dom.parentNode;
14281 var nodeName = target.nodeName;
14282 var className = target.className;
14283 var html = target.innerHTML;
14285 switch(nodeName.toLowerCase()) {
14287 switch(className) {
14293 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14294 switch(this.viewMode){
14296 this.viewDate = this.moveMonth(this.viewDate, dir);
14300 this.viewDate = this.moveYear(this.viewDate, dir);
14306 var date = new Date();
14307 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14309 this.setValue(this.formatDate(this.date));
14316 if (className.indexOf('disabled') === -1) {
14317 this.viewDate.setUTCDate(1);
14318 if (className.indexOf('month') !== -1) {
14319 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14321 var year = parseInt(html, 10) || 0;
14322 this.viewDate.setUTCFullYear(year);
14331 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14332 var day = parseInt(html, 10) || 1;
14333 var year = this.viewDate.getUTCFullYear(),
14334 month = this.viewDate.getUTCMonth();
14336 if (className.indexOf('old') !== -1) {
14343 } else if (className.indexOf('new') !== -1) {
14351 this.date = this.UTCDate(year, month, day,0,0,0,0);
14352 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14354 this.setValue(this.formatDate(this.date));
14361 setStartDate: function(startDate)
14363 this.startDate = startDate || -Infinity;
14364 if (this.startDate !== -Infinity) {
14365 this.startDate = this.parseDate(this.startDate);
14368 this.updateNavArrows();
14371 setEndDate: function(endDate)
14373 this.endDate = endDate || Infinity;
14374 if (this.endDate !== Infinity) {
14375 this.endDate = this.parseDate(this.endDate);
14378 this.updateNavArrows();
14381 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14383 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14384 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14385 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14387 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14388 return parseInt(d, 10);
14391 this.updateNavArrows();
14394 updateNavArrows: function()
14396 var d = new Date(this.viewDate),
14397 year = d.getUTCFullYear(),
14398 month = d.getUTCMonth();
14400 Roo.each(this.picker().select('.prev', true).elements, function(v){
14402 switch (this.viewMode) {
14405 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14411 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14418 Roo.each(this.picker().select('.next', true).elements, function(v){
14420 switch (this.viewMode) {
14423 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14429 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14437 moveMonth: function(date, dir)
14439 if (!dir) return date;
14440 var new_date = new Date(date.valueOf()),
14441 day = new_date.getUTCDate(),
14442 month = new_date.getUTCMonth(),
14443 mag = Math.abs(dir),
14445 dir = dir > 0 ? 1 : -1;
14448 // If going back one month, make sure month is not current month
14449 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14451 return new_date.getUTCMonth() == month;
14453 // If going forward one month, make sure month is as expected
14454 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14456 return new_date.getUTCMonth() != new_month;
14458 new_month = month + dir;
14459 new_date.setUTCMonth(new_month);
14460 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14461 if (new_month < 0 || new_month > 11)
14462 new_month = (new_month + 12) % 12;
14464 // For magnitudes >1, move one month at a time...
14465 for (var i=0; i<mag; i++)
14466 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14467 new_date = this.moveMonth(new_date, dir);
14468 // ...then reset the day, keeping it in the new month
14469 new_month = new_date.getUTCMonth();
14470 new_date.setUTCDate(day);
14472 return new_month != new_date.getUTCMonth();
14475 // Common date-resetting loop -- if date is beyond end of month, make it
14478 new_date.setUTCDate(--day);
14479 new_date.setUTCMonth(new_month);
14484 moveYear: function(date, dir)
14486 return this.moveMonth(date, dir*12);
14489 dateWithinRange: function(date)
14491 return date >= this.startDate && date <= this.endDate;
14497 this.picker().remove();
14502 Roo.apply(Roo.bootstrap.DateField, {
14513 html: '<i class="fa fa-arrow-left"/>'
14523 html: '<i class="fa fa-arrow-right"/>'
14565 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14566 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14567 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14568 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14569 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14582 navFnc: 'FullYear',
14587 navFnc: 'FullYear',
14592 Roo.apply(Roo.bootstrap.DateField, {
14596 cls: 'datepicker dropdown-menu',
14600 cls: 'datepicker-days',
14604 cls: 'table-condensed',
14606 Roo.bootstrap.DateField.head,
14610 Roo.bootstrap.DateField.footer
14617 cls: 'datepicker-months',
14621 cls: 'table-condensed',
14623 Roo.bootstrap.DateField.head,
14624 Roo.bootstrap.DateField.content,
14625 Roo.bootstrap.DateField.footer
14632 cls: 'datepicker-years',
14636 cls: 'table-condensed',
14638 Roo.bootstrap.DateField.head,
14639 Roo.bootstrap.DateField.content,
14640 Roo.bootstrap.DateField.footer
14659 * @class Roo.bootstrap.TimeField
14660 * @extends Roo.bootstrap.Input
14661 * Bootstrap DateField class
14665 * Create a new TimeField
14666 * @param {Object} config The config object
14669 Roo.bootstrap.TimeField = function(config){
14670 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14674 * Fires when this field show.
14675 * @param {Roo.bootstrap.DateField} this
14676 * @param {Mixed} date The date value
14681 * Fires when this field hide.
14682 * @param {Roo.bootstrap.DateField} this
14683 * @param {Mixed} date The date value
14688 * Fires when select a date.
14689 * @param {Roo.bootstrap.DateField} this
14690 * @param {Mixed} date The date value
14696 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14699 * @cfg {String} format
14700 * The default time format string which can be overriden for localization support. The format must be
14701 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14705 onRender: function(ct, position)
14708 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14710 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14712 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14714 this.pop = this.picker().select('>.datepicker-time',true).first();
14715 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14717 this.picker().on('mousedown', this.onMousedown, this);
14718 this.picker().on('click', this.onClick, this);
14720 this.picker().addClass('datepicker-dropdown');
14725 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14726 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14727 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14728 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14729 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14730 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14734 fireKey: function(e){
14735 if (!this.picker().isVisible()){
14736 if (e.keyCode == 27) // allow escape to hide and re-show picker
14741 e.preventDefault();
14749 this.onTogglePeriod();
14752 this.onIncrementMinutes();
14755 this.onDecrementMinutes();
14764 onClick: function(e) {
14765 e.stopPropagation();
14766 e.preventDefault();
14769 picker : function()
14771 return this.el.select('.datepicker', true).first();
14774 fillTime: function()
14776 var time = this.pop.select('tbody', true).first();
14778 time.dom.innerHTML = '';
14793 cls: 'hours-up glyphicon glyphicon-chevron-up'
14813 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14834 cls: 'timepicker-hour',
14849 cls: 'timepicker-minute',
14864 cls: 'btn btn-primary period',
14886 cls: 'hours-down glyphicon glyphicon-chevron-down'
14906 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14924 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14931 var hours = this.time.getHours();
14932 var minutes = this.time.getMinutes();
14945 hours = hours - 12;
14949 hours = '0' + hours;
14953 minutes = '0' + minutes;
14956 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14957 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14958 this.pop.select('button', true).first().dom.innerHTML = period;
14964 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14966 var cls = ['bottom'];
14968 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14975 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14980 this.picker().addClass(cls.join('-'));
14984 Roo.each(cls, function(c){
14986 _this.picker().setTop(_this.inputEl().getHeight());
14990 _this.picker().setTop(0 - _this.picker().getHeight());
14995 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14999 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15006 onFocus : function()
15008 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15012 onBlur : function()
15014 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15020 this.picker().show();
15025 this.fireEvent('show', this, this.date);
15030 this.picker().hide();
15033 this.fireEvent('hide', this, this.date);
15036 setTime : function()
15039 this.setValue(this.time.format(this.format));
15041 this.fireEvent('select', this, this.date);
15046 onMousedown: function(e){
15047 e.stopPropagation();
15048 e.preventDefault();
15051 onIncrementHours: function()
15053 Roo.log('onIncrementHours');
15054 this.time = this.time.add(Date.HOUR, 1);
15059 onDecrementHours: function()
15061 Roo.log('onDecrementHours');
15062 this.time = this.time.add(Date.HOUR, -1);
15066 onIncrementMinutes: function()
15068 Roo.log('onIncrementMinutes');
15069 this.time = this.time.add(Date.MINUTE, 1);
15073 onDecrementMinutes: function()
15075 Roo.log('onDecrementMinutes');
15076 this.time = this.time.add(Date.MINUTE, -1);
15080 onTogglePeriod: function()
15082 Roo.log('onTogglePeriod');
15083 this.time = this.time.add(Date.HOUR, 12);
15090 Roo.apply(Roo.bootstrap.TimeField, {
15120 cls: 'btn btn-info ok',
15132 Roo.apply(Roo.bootstrap.TimeField, {
15136 cls: 'datepicker dropdown-menu',
15140 cls: 'datepicker-time',
15144 cls: 'table-condensed',
15146 Roo.bootstrap.TimeField.content,
15147 Roo.bootstrap.TimeField.footer
15166 * @class Roo.bootstrap.CheckBox
15167 * @extends Roo.bootstrap.Input
15168 * Bootstrap CheckBox class
15170 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15171 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15172 * @cfg {String} boxLabel The text that appears beside the checkbox
15173 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15174 * @cfg {Boolean} checked initnal the element
15178 * Create a new CheckBox
15179 * @param {Object} config The config object
15182 Roo.bootstrap.CheckBox = function(config){
15183 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15188 * Fires when the element is checked or unchecked.
15189 * @param {Roo.bootstrap.CheckBox} this This input
15190 * @param {Boolean} checked The new checked value
15196 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15198 inputType: 'checkbox',
15205 getAutoCreate : function()
15207 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15213 cfg.cls = 'form-group checkbox' //input-group
15221 type : this.inputType,
15222 value : (!this.checked) ? this.valueOff : this.inputValue,
15223 cls : 'roo-checkbox', //'form-box',
15224 placeholder : this.placeholder || ''
15228 if (this.weight) { // Validity check?
15229 cfg.cls += " checkbox-" + this.weight;
15232 if (this.disabled) {
15233 input.disabled=true;
15237 input.checked = this.checked;
15241 input.name = this.name;
15245 input.cls += ' input-' + this.size;
15249 ['xs','sm','md','lg'].map(function(size){
15250 if (settings[size]) {
15251 cfg.cls += ' col-' + size + '-' + settings[size];
15257 var inputblock = input;
15262 if (this.before || this.after) {
15265 cls : 'input-group',
15269 inputblock.cn.push({
15271 cls : 'input-group-addon',
15275 inputblock.cn.push(input);
15277 inputblock.cn.push({
15279 cls : 'input-group-addon',
15286 if (align ==='left' && this.fieldLabel.length) {
15287 Roo.log("left and has label");
15293 cls : 'control-label col-md-' + this.labelWidth,
15294 html : this.fieldLabel
15298 cls : "col-md-" + (12 - this.labelWidth),
15305 } else if ( this.fieldLabel.length) {
15310 tag: this.boxLabel ? 'span' : 'label',
15312 cls: 'control-label box-input-label',
15313 //cls : 'input-group-addon',
15314 html : this.fieldLabel
15324 Roo.log(" no label && no align");
15325 cfg.cn = [ inputblock ] ;
15334 html: this.boxLabel
15346 * return the real input element.
15348 inputEl: function ()
15350 return this.el.select('input.roo-checkbox',true).first();
15355 return this.el.select('label.control-label',true).first();
15358 initEvents : function()
15360 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15362 this.inputEl().on('click', this.onClick, this);
15366 onClick : function()
15368 this.setChecked(!this.checked);
15371 setChecked : function(state,suppressEvent)
15373 this.checked = state;
15375 this.inputEl().dom.checked = state;
15377 if(suppressEvent !== true){
15378 this.fireEvent('check', this, state);
15381 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15385 setValue : function(v,suppressEvent)
15387 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15401 * @class Roo.bootstrap.Radio
15402 * @extends Roo.bootstrap.CheckBox
15403 * Bootstrap Radio class
15406 * Create a new Radio
15407 * @param {Object} config The config object
15410 Roo.bootstrap.Radio = function(config){
15411 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15415 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15417 inputType: 'radio',
15421 getAutoCreate : function()
15423 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15429 cfg.cls = 'form-group radio' //input-group
15434 type : this.inputType,
15435 value : (!this.checked) ? this.valueOff : this.inputValue,
15437 placeholder : this.placeholder || ''
15440 if (this.weight) { // Validity check?
15441 cfg.cls += " radio-" + this.weight;
15443 if (this.disabled) {
15444 input.disabled=true;
15448 input.checked = this.checked;
15452 input.name = this.name;
15456 input.cls += ' input-' + this.size;
15460 ['xs','sm','md','lg'].map(function(size){
15461 if (settings[size]) {
15462 cfg.cls += ' col-' + size + '-' + settings[size];
15466 var inputblock = input;
15468 if (this.before || this.after) {
15471 cls : 'input-group',
15475 inputblock.cn.push({
15477 cls : 'input-group-addon',
15481 inputblock.cn.push(input);
15483 inputblock.cn.push({
15485 cls : 'input-group-addon',
15492 if (align ==='left' && this.fieldLabel.length) {
15493 Roo.log("left and has label");
15499 cls : 'control-label col-md-' + this.labelWidth,
15500 html : this.fieldLabel
15504 cls : "col-md-" + (12 - this.labelWidth),
15511 } else if ( this.fieldLabel.length) {
15518 cls: 'control-label box-input-label',
15519 //cls : 'input-group-addon',
15520 html : this.fieldLabel
15530 Roo.log(" no label && no align");
15545 html: this.boxLabel
15552 inputEl: function ()
15554 return this.el.select('input.roo-radio',true).first();
15556 onClick : function()
15558 this.setChecked(true);
15561 setChecked : function(state,suppressEvent)
15564 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15565 v.dom.checked = false;
15569 this.checked = state;
15570 this.inputEl().dom.checked = state;
15572 if(suppressEvent !== true){
15573 this.fireEvent('check', this, state);
15576 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15580 getGroupValue : function()
15583 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15584 if(v.dom.checked == true){
15585 value = v.dom.value;
15593 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15594 * @return {Mixed} value The field value
15596 getValue : function(){
15597 return this.getGroupValue();
15603 //<script type="text/javascript">
15606 * Based Ext JS Library 1.1.1
15607 * Copyright(c) 2006-2007, Ext JS, LLC.
15613 * @class Roo.HtmlEditorCore
15614 * @extends Roo.Component
15615 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15617 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15620 Roo.HtmlEditorCore = function(config){
15623 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15626 * @event initialize
15627 * Fires when the editor is fully initialized (including the iframe)
15628 * @param {Roo.HtmlEditorCore} this
15633 * Fires when the editor is first receives the focus. Any insertion must wait
15634 * until after this event.
15635 * @param {Roo.HtmlEditorCore} this
15639 * @event beforesync
15640 * Fires before the textarea is updated with content from the editor iframe. Return false
15641 * to cancel the sync.
15642 * @param {Roo.HtmlEditorCore} this
15643 * @param {String} html
15647 * @event beforepush
15648 * Fires before the iframe editor is updated with content from the textarea. Return false
15649 * to cancel the push.
15650 * @param {Roo.HtmlEditorCore} this
15651 * @param {String} html
15656 * Fires when the textarea is updated with content from the editor iframe.
15657 * @param {Roo.HtmlEditorCore} this
15658 * @param {String} html
15663 * Fires when the iframe editor is updated with content from the textarea.
15664 * @param {Roo.HtmlEditorCore} this
15665 * @param {String} html
15670 * @event editorevent
15671 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15672 * @param {Roo.HtmlEditorCore} this
15680 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15684 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15690 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15695 * @cfg {Number} height (in pixels)
15699 * @cfg {Number} width (in pixels)
15704 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15707 stylesheets: false,
15712 // private properties
15713 validationEvent : false,
15715 initialized : false,
15717 sourceEditMode : false,
15718 onFocus : Roo.emptyFn,
15720 hideMode:'offsets',
15728 * Protected method that will not generally be called directly. It
15729 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15730 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15732 getDocMarkup : function(){
15735 Roo.log(this.stylesheets);
15737 // inherit styels from page...??
15738 if (this.stylesheets === false) {
15740 Roo.get(document.head).select('style').each(function(node) {
15741 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15744 Roo.get(document.head).select('link').each(function(node) {
15745 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15748 } else if (!this.stylesheets.length) {
15750 st = '<style type="text/css">' +
15751 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15754 Roo.each(this.stylesheets, function(s) {
15755 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15760 st += '<style type="text/css">' +
15761 'IMG { cursor: pointer } ' +
15765 return '<html><head>' + st +
15766 //<style type="text/css">' +
15767 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15769 ' </head><body class="roo-htmleditor-body"></body></html>';
15773 onRender : function(ct, position)
15776 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15777 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15780 this.el.dom.style.border = '0 none';
15781 this.el.dom.setAttribute('tabIndex', -1);
15782 this.el.addClass('x-hidden hide');
15786 if(Roo.isIE){ // fix IE 1px bogus margin
15787 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15791 this.frameId = Roo.id();
15795 var iframe = this.owner.wrap.createChild({
15797 cls: 'form-control', // bootstrap..
15799 name: this.frameId,
15800 frameBorder : 'no',
15801 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15806 this.iframe = iframe.dom;
15808 this.assignDocWin();
15810 this.doc.designMode = 'on';
15813 this.doc.write(this.getDocMarkup());
15817 var task = { // must defer to wait for browser to be ready
15819 //console.log("run task?" + this.doc.readyState);
15820 this.assignDocWin();
15821 if(this.doc.body || this.doc.readyState == 'complete'){
15823 this.doc.designMode="on";
15827 Roo.TaskMgr.stop(task);
15828 this.initEditor.defer(10, this);
15835 Roo.TaskMgr.start(task);
15842 onResize : function(w, h)
15844 Roo.log('resize: ' +w + ',' + h );
15845 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15849 if(typeof w == 'number'){
15851 this.iframe.style.width = w + 'px';
15853 if(typeof h == 'number'){
15855 this.iframe.style.height = h + 'px';
15857 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15864 * Toggles the editor between standard and source edit mode.
15865 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15867 toggleSourceEdit : function(sourceEditMode){
15869 this.sourceEditMode = sourceEditMode === true;
15871 if(this.sourceEditMode){
15873 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15876 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15877 //this.iframe.className = '';
15880 //this.setSize(this.owner.wrap.getSize());
15881 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15888 * Protected method that will not generally be called directly. If you need/want
15889 * custom HTML cleanup, this is the method you should override.
15890 * @param {String} html The HTML to be cleaned
15891 * return {String} The cleaned HTML
15893 cleanHtml : function(html){
15894 html = String(html);
15895 if(html.length > 5){
15896 if(Roo.isSafari){ // strip safari nonsense
15897 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15900 if(html == ' '){
15907 * HTML Editor -> Textarea
15908 * Protected method that will not generally be called directly. Syncs the contents
15909 * of the editor iframe with the textarea.
15911 syncValue : function(){
15912 if(this.initialized){
15913 var bd = (this.doc.body || this.doc.documentElement);
15914 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15915 var html = bd.innerHTML;
15917 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15918 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15920 html = '<div style="'+m[0]+'">' + html + '</div>';
15923 html = this.cleanHtml(html);
15924 // fix up the special chars.. normaly like back quotes in word...
15925 // however we do not want to do this with chinese..
15926 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15927 var cc = b.charCodeAt();
15929 (cc >= 0x4E00 && cc < 0xA000 ) ||
15930 (cc >= 0x3400 && cc < 0x4E00 ) ||
15931 (cc >= 0xf900 && cc < 0xfb00 )
15937 if(this.owner.fireEvent('beforesync', this, html) !== false){
15938 this.el.dom.value = html;
15939 this.owner.fireEvent('sync', this, html);
15945 * Protected method that will not generally be called directly. Pushes the value of the textarea
15946 * into the iframe editor.
15948 pushValue : function(){
15949 if(this.initialized){
15950 var v = this.el.dom.value.trim();
15952 // if(v.length < 1){
15956 if(this.owner.fireEvent('beforepush', this, v) !== false){
15957 var d = (this.doc.body || this.doc.documentElement);
15959 this.cleanUpPaste();
15960 this.el.dom.value = d.innerHTML;
15961 this.owner.fireEvent('push', this, v);
15967 deferFocus : function(){
15968 this.focus.defer(10, this);
15972 focus : function(){
15973 if(this.win && !this.sourceEditMode){
15980 assignDocWin: function()
15982 var iframe = this.iframe;
15985 this.doc = iframe.contentWindow.document;
15986 this.win = iframe.contentWindow;
15988 if (!Roo.get(this.frameId)) {
15991 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15992 this.win = Roo.get(this.frameId).dom.contentWindow;
15997 initEditor : function(){
15998 //console.log("INIT EDITOR");
15999 this.assignDocWin();
16003 this.doc.designMode="on";
16005 this.doc.write(this.getDocMarkup());
16008 var dbody = (this.doc.body || this.doc.documentElement);
16009 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16010 // this copies styles from the containing element into thsi one..
16011 // not sure why we need all of this..
16012 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16014 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16015 //ss['background-attachment'] = 'fixed'; // w3c
16016 dbody.bgProperties = 'fixed'; // ie
16017 //Roo.DomHelper.applyStyles(dbody, ss);
16018 Roo.EventManager.on(this.doc, {
16019 //'mousedown': this.onEditorEvent,
16020 'mouseup': this.onEditorEvent,
16021 'dblclick': this.onEditorEvent,
16022 'click': this.onEditorEvent,
16023 'keyup': this.onEditorEvent,
16028 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16030 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16031 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16033 this.initialized = true;
16035 this.owner.fireEvent('initialize', this);
16040 onDestroy : function(){
16046 //for (var i =0; i < this.toolbars.length;i++) {
16047 // // fixme - ask toolbars for heights?
16048 // this.toolbars[i].onDestroy();
16051 //this.wrap.dom.innerHTML = '';
16052 //this.wrap.remove();
16057 onFirstFocus : function(){
16059 this.assignDocWin();
16062 this.activated = true;
16065 if(Roo.isGecko){ // prevent silly gecko errors
16067 var s = this.win.getSelection();
16068 if(!s.focusNode || s.focusNode.nodeType != 3){
16069 var r = s.getRangeAt(0);
16070 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16075 this.execCmd('useCSS', true);
16076 this.execCmd('styleWithCSS', false);
16079 this.owner.fireEvent('activate', this);
16083 adjustFont: function(btn){
16084 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16085 //if(Roo.isSafari){ // safari
16088 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16089 if(Roo.isSafari){ // safari
16090 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16091 v = (v < 10) ? 10 : v;
16092 v = (v > 48) ? 48 : v;
16093 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16098 v = Math.max(1, v+adjust);
16100 this.execCmd('FontSize', v );
16103 onEditorEvent : function(e){
16104 this.owner.fireEvent('editorevent', this, e);
16105 // this.updateToolbar();
16106 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16109 insertTag : function(tg)
16111 // could be a bit smarter... -> wrap the current selected tRoo..
16112 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16114 range = this.createRange(this.getSelection());
16115 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16116 wrappingNode.appendChild(range.extractContents());
16117 range.insertNode(wrappingNode);
16124 this.execCmd("formatblock", tg);
16128 insertText : function(txt)
16132 var range = this.createRange();
16133 range.deleteContents();
16134 //alert(Sender.getAttribute('label'));
16136 range.insertNode(this.doc.createTextNode(txt));
16142 * Executes a Midas editor command on the editor document and performs necessary focus and
16143 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16144 * @param {String} cmd The Midas command
16145 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16147 relayCmd : function(cmd, value){
16149 this.execCmd(cmd, value);
16150 this.owner.fireEvent('editorevent', this);
16151 //this.updateToolbar();
16152 this.owner.deferFocus();
16156 * Executes a Midas editor command directly on the editor document.
16157 * For visual commands, you should use {@link #relayCmd} instead.
16158 * <b>This should only be called after the editor is initialized.</b>
16159 * @param {String} cmd The Midas command
16160 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16162 execCmd : function(cmd, value){
16163 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16170 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16172 * @param {String} text | dom node..
16174 insertAtCursor : function(text)
16179 if(!this.activated){
16185 var r = this.doc.selection.createRange();
16196 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16200 // from jquery ui (MIT licenced)
16202 var win = this.win;
16204 if (win.getSelection && win.getSelection().getRangeAt) {
16205 range = win.getSelection().getRangeAt(0);
16206 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16207 range.insertNode(node);
16208 } else if (win.document.selection && win.document.selection.createRange) {
16209 // no firefox support
16210 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16211 win.document.selection.createRange().pasteHTML(txt);
16213 // no firefox support
16214 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16215 this.execCmd('InsertHTML', txt);
16224 mozKeyPress : function(e){
16226 var c = e.getCharCode(), cmd;
16229 c = String.fromCharCode(c).toLowerCase();
16243 this.cleanUpPaste.defer(100, this);
16251 e.preventDefault();
16259 fixKeys : function(){ // load time branching for fastest keydown performance
16261 return function(e){
16262 var k = e.getKey(), r;
16265 r = this.doc.selection.createRange();
16268 r.pasteHTML('    ');
16275 r = this.doc.selection.createRange();
16277 var target = r.parentElement();
16278 if(!target || target.tagName.toLowerCase() != 'li'){
16280 r.pasteHTML('<br />');
16286 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16287 this.cleanUpPaste.defer(100, this);
16293 }else if(Roo.isOpera){
16294 return function(e){
16295 var k = e.getKey();
16299 this.execCmd('InsertHTML','    ');
16302 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16303 this.cleanUpPaste.defer(100, this);
16308 }else if(Roo.isSafari){
16309 return function(e){
16310 var k = e.getKey();
16314 this.execCmd('InsertText','\t');
16318 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16319 this.cleanUpPaste.defer(100, this);
16327 getAllAncestors: function()
16329 var p = this.getSelectedNode();
16332 a.push(p); // push blank onto stack..
16333 p = this.getParentElement();
16337 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16341 a.push(this.doc.body);
16345 lastSelNode : false,
16348 getSelection : function()
16350 this.assignDocWin();
16351 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16354 getSelectedNode: function()
16356 // this may only work on Gecko!!!
16358 // should we cache this!!!!
16363 var range = this.createRange(this.getSelection()).cloneRange();
16366 var parent = range.parentElement();
16368 var testRange = range.duplicate();
16369 testRange.moveToElementText(parent);
16370 if (testRange.inRange(range)) {
16373 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16376 parent = parent.parentElement;
16381 // is ancestor a text element.
16382 var ac = range.commonAncestorContainer;
16383 if (ac.nodeType == 3) {
16384 ac = ac.parentNode;
16387 var ar = ac.childNodes;
16390 var other_nodes = [];
16391 var has_other_nodes = false;
16392 for (var i=0;i<ar.length;i++) {
16393 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16396 // fullly contained node.
16398 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16403 // probably selected..
16404 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16405 other_nodes.push(ar[i]);
16409 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16414 has_other_nodes = true;
16416 if (!nodes.length && other_nodes.length) {
16417 nodes= other_nodes;
16419 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16425 createRange: function(sel)
16427 // this has strange effects when using with
16428 // top toolbar - not sure if it's a great idea.
16429 //this.editor.contentWindow.focus();
16430 if (typeof sel != "undefined") {
16432 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16434 return this.doc.createRange();
16437 return this.doc.createRange();
16440 getParentElement: function()
16443 this.assignDocWin();
16444 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16446 var range = this.createRange(sel);
16449 var p = range.commonAncestorContainer;
16450 while (p.nodeType == 3) { // text node
16461 * Range intersection.. the hard stuff...
16465 * [ -- selected range --- ]
16469 * if end is before start or hits it. fail.
16470 * if start is after end or hits it fail.
16472 * if either hits (but other is outside. - then it's not
16478 // @see http://www.thismuchiknow.co.uk/?p=64.
16479 rangeIntersectsNode : function(range, node)
16481 var nodeRange = node.ownerDocument.createRange();
16483 nodeRange.selectNode(node);
16485 nodeRange.selectNodeContents(node);
16488 var rangeStartRange = range.cloneRange();
16489 rangeStartRange.collapse(true);
16491 var rangeEndRange = range.cloneRange();
16492 rangeEndRange.collapse(false);
16494 var nodeStartRange = nodeRange.cloneRange();
16495 nodeStartRange.collapse(true);
16497 var nodeEndRange = nodeRange.cloneRange();
16498 nodeEndRange.collapse(false);
16500 return rangeStartRange.compareBoundaryPoints(
16501 Range.START_TO_START, nodeEndRange) == -1 &&
16502 rangeEndRange.compareBoundaryPoints(
16503 Range.START_TO_START, nodeStartRange) == 1;
16507 rangeCompareNode : function(range, node)
16509 var nodeRange = node.ownerDocument.createRange();
16511 nodeRange.selectNode(node);
16513 nodeRange.selectNodeContents(node);
16517 range.collapse(true);
16519 nodeRange.collapse(true);
16521 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16522 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16524 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16526 var nodeIsBefore = ss == 1;
16527 var nodeIsAfter = ee == -1;
16529 if (nodeIsBefore && nodeIsAfter)
16531 if (!nodeIsBefore && nodeIsAfter)
16532 return 1; //right trailed.
16534 if (nodeIsBefore && !nodeIsAfter)
16535 return 2; // left trailed.
16540 // private? - in a new class?
16541 cleanUpPaste : function()
16543 // cleans up the whole document..
16544 Roo.log('cleanuppaste');
16546 this.cleanUpChildren(this.doc.body);
16547 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16548 if (clean != this.doc.body.innerHTML) {
16549 this.doc.body.innerHTML = clean;
16554 cleanWordChars : function(input) {// change the chars to hex code
16555 var he = Roo.HtmlEditorCore;
16557 var output = input;
16558 Roo.each(he.swapCodes, function(sw) {
16559 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16561 output = output.replace(swapper, sw[1]);
16568 cleanUpChildren : function (n)
16570 if (!n.childNodes.length) {
16573 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16574 this.cleanUpChild(n.childNodes[i]);
16581 cleanUpChild : function (node)
16584 //console.log(node);
16585 if (node.nodeName == "#text") {
16586 // clean up silly Windows -- stuff?
16589 if (node.nodeName == "#comment") {
16590 node.parentNode.removeChild(node);
16591 // clean up silly Windows -- stuff?
16595 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16597 node.parentNode.removeChild(node);
16602 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16604 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16605 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16607 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16608 // remove_keep_children = true;
16611 if (remove_keep_children) {
16612 this.cleanUpChildren(node);
16613 // inserts everything just before this node...
16614 while (node.childNodes.length) {
16615 var cn = node.childNodes[0];
16616 node.removeChild(cn);
16617 node.parentNode.insertBefore(cn, node);
16619 node.parentNode.removeChild(node);
16623 if (!node.attributes || !node.attributes.length) {
16624 this.cleanUpChildren(node);
16628 function cleanAttr(n,v)
16631 if (v.match(/^\./) || v.match(/^\//)) {
16634 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16637 if (v.match(/^#/)) {
16640 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16641 node.removeAttribute(n);
16645 function cleanStyle(n,v)
16647 if (v.match(/expression/)) { //XSS?? should we even bother..
16648 node.removeAttribute(n);
16651 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16652 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16655 var parts = v.split(/;/);
16658 Roo.each(parts, function(p) {
16659 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16663 var l = p.split(':').shift().replace(/\s+/g,'');
16664 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16666 if ( cblack.indexOf(l) > -1) {
16667 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16668 //node.removeAttribute(n);
16672 // only allow 'c whitelisted system attributes'
16673 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16674 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16675 //node.removeAttribute(n);
16685 if (clean.length) {
16686 node.setAttribute(n, clean.join(';'));
16688 node.removeAttribute(n);
16694 for (var i = node.attributes.length-1; i > -1 ; i--) {
16695 var a = node.attributes[i];
16698 if (a.name.toLowerCase().substr(0,2)=='on') {
16699 node.removeAttribute(a.name);
16702 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16703 node.removeAttribute(a.name);
16706 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16707 cleanAttr(a.name,a.value); // fixme..
16710 if (a.name == 'style') {
16711 cleanStyle(a.name,a.value);
16714 /// clean up MS crap..
16715 // tecnically this should be a list of valid class'es..
16718 if (a.name == 'class') {
16719 if (a.value.match(/^Mso/)) {
16720 node.className = '';
16723 if (a.value.match(/body/)) {
16724 node.className = '';
16735 this.cleanUpChildren(node);
16740 * Clean up MS wordisms...
16742 cleanWord : function(node)
16745 var cleanWordChildren = function()
16747 if (!node.childNodes.length) {
16750 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16751 _t.cleanWord(node.childNodes[i]);
16757 this.cleanWord(this.doc.body);
16760 if (node.nodeName == "#text") {
16761 // clean up silly Windows -- stuff?
16764 if (node.nodeName == "#comment") {
16765 node.parentNode.removeChild(node);
16766 // clean up silly Windows -- stuff?
16770 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16771 node.parentNode.removeChild(node);
16775 // remove - but keep children..
16776 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16777 while (node.childNodes.length) {
16778 var cn = node.childNodes[0];
16779 node.removeChild(cn);
16780 node.parentNode.insertBefore(cn, node);
16782 node.parentNode.removeChild(node);
16783 cleanWordChildren();
16787 if (node.className.length) {
16789 var cn = node.className.split(/\W+/);
16791 Roo.each(cn, function(cls) {
16792 if (cls.match(/Mso[a-zA-Z]+/)) {
16797 node.className = cna.length ? cna.join(' ') : '';
16799 node.removeAttribute("class");
16803 if (node.hasAttribute("lang")) {
16804 node.removeAttribute("lang");
16807 if (node.hasAttribute("style")) {
16809 var styles = node.getAttribute("style").split(";");
16811 Roo.each(styles, function(s) {
16812 if (!s.match(/:/)) {
16815 var kv = s.split(":");
16816 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16819 // what ever is left... we allow.
16822 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16823 if (!nstyle.length) {
16824 node.removeAttribute('style');
16828 cleanWordChildren();
16832 domToHTML : function(currentElement, depth, nopadtext) {
16834 depth = depth || 0;
16835 nopadtext = nopadtext || false;
16837 if (!currentElement) {
16838 return this.domToHTML(this.doc.body);
16841 //Roo.log(currentElement);
16843 var allText = false;
16844 var nodeName = currentElement.nodeName;
16845 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16847 if (nodeName == '#text') {
16848 return currentElement.nodeValue;
16853 if (nodeName != 'BODY') {
16856 // Prints the node tagName, such as <A>, <IMG>, etc
16859 for(i = 0; i < currentElement.attributes.length;i++) {
16861 var aname = currentElement.attributes.item(i).name;
16862 if (!currentElement.attributes.item(i).value.length) {
16865 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16868 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16877 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16880 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16885 // Traverse the tree
16887 var currentElementChild = currentElement.childNodes.item(i);
16888 var allText = true;
16889 var innerHTML = '';
16891 while (currentElementChild) {
16892 // Formatting code (indent the tree so it looks nice on the screen)
16893 var nopad = nopadtext;
16894 if (lastnode == 'SPAN') {
16898 if (currentElementChild.nodeName == '#text') {
16899 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16900 if (!nopad && toadd.length > 80) {
16901 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16903 innerHTML += toadd;
16906 currentElementChild = currentElement.childNodes.item(i);
16912 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16914 // Recursively traverse the tree structure of the child node
16915 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16916 lastnode = currentElementChild.nodeName;
16918 currentElementChild=currentElement.childNodes.item(i);
16924 // The remaining code is mostly for formatting the tree
16925 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16930 ret+= "</"+tagName+">";
16936 // hide stuff that is not compatible
16950 * @event specialkey
16954 * @cfg {String} fieldClass @hide
16957 * @cfg {String} focusClass @hide
16960 * @cfg {String} autoCreate @hide
16963 * @cfg {String} inputType @hide
16966 * @cfg {String} invalidClass @hide
16969 * @cfg {String} invalidText @hide
16972 * @cfg {String} msgFx @hide
16975 * @cfg {String} validateOnBlur @hide
16979 Roo.HtmlEditorCore.white = [
16980 'area', 'br', 'img', 'input', 'hr', 'wbr',
16982 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16983 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16984 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16985 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16986 'table', 'ul', 'xmp',
16988 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16991 'dir', 'menu', 'ol', 'ul', 'dl',
16997 Roo.HtmlEditorCore.black = [
16998 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17000 'base', 'basefont', 'bgsound', 'blink', 'body',
17001 'frame', 'frameset', 'head', 'html', 'ilayer',
17002 'iframe', 'layer', 'link', 'meta', 'object',
17003 'script', 'style' ,'title', 'xml' // clean later..
17005 Roo.HtmlEditorCore.clean = [
17006 'script', 'style', 'title', 'xml'
17008 Roo.HtmlEditorCore.remove = [
17013 Roo.HtmlEditorCore.ablack = [
17017 Roo.HtmlEditorCore.aclean = [
17018 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17022 Roo.HtmlEditorCore.pwhite= [
17023 'http', 'https', 'mailto'
17026 // white listed style attributes.
17027 Roo.HtmlEditorCore.cwhite= [
17028 // 'text-align', /// default is to allow most things..
17034 // black listed style attributes.
17035 Roo.HtmlEditorCore.cblack= [
17036 // 'font-size' -- this can be set by the project
17040 Roo.HtmlEditorCore.swapCodes =[
17059 * @class Roo.bootstrap.HtmlEditor
17060 * @extends Roo.bootstrap.TextArea
17061 * Bootstrap HtmlEditor class
17064 * Create a new HtmlEditor
17065 * @param {Object} config The config object
17068 Roo.bootstrap.HtmlEditor = function(config){
17069 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17070 if (!this.toolbars) {
17071 this.toolbars = [];
17073 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17076 * @event initialize
17077 * Fires when the editor is fully initialized (including the iframe)
17078 * @param {HtmlEditor} this
17083 * Fires when the editor is first receives the focus. Any insertion must wait
17084 * until after this event.
17085 * @param {HtmlEditor} this
17089 * @event beforesync
17090 * Fires before the textarea is updated with content from the editor iframe. Return false
17091 * to cancel the sync.
17092 * @param {HtmlEditor} this
17093 * @param {String} html
17097 * @event beforepush
17098 * Fires before the iframe editor is updated with content from the textarea. Return false
17099 * to cancel the push.
17100 * @param {HtmlEditor} this
17101 * @param {String} html
17106 * Fires when the textarea is updated with content from the editor iframe.
17107 * @param {HtmlEditor} this
17108 * @param {String} html
17113 * Fires when the iframe editor is updated with content from the textarea.
17114 * @param {HtmlEditor} this
17115 * @param {String} html
17119 * @event editmodechange
17120 * Fires when the editor switches edit modes
17121 * @param {HtmlEditor} this
17122 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17124 editmodechange: true,
17126 * @event editorevent
17127 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17128 * @param {HtmlEditor} this
17132 * @event firstfocus
17133 * Fires when on first focus - needed by toolbars..
17134 * @param {HtmlEditor} this
17139 * Auto save the htmlEditor value as a file into Events
17140 * @param {HtmlEditor} this
17144 * @event savedpreview
17145 * preview the saved version of htmlEditor
17146 * @param {HtmlEditor} this
17153 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17157 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17162 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17167 * @cfg {Number} height (in pixels)
17171 * @cfg {Number} width (in pixels)
17176 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17179 stylesheets: false,
17184 // private properties
17185 validationEvent : false,
17187 initialized : false,
17190 onFocus : Roo.emptyFn,
17192 hideMode:'offsets',
17195 tbContainer : false,
17197 toolbarContainer :function() {
17198 return this.wrap.select('.x-html-editor-tb',true).first();
17202 * Protected method that will not generally be called directly. It
17203 * is called when the editor creates its toolbar. Override this method if you need to
17204 * add custom toolbar buttons.
17205 * @param {HtmlEditor} editor
17207 createToolbar : function(){
17209 Roo.log("create toolbars");
17211 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17212 this.toolbars[0].render(this.toolbarContainer());
17216 // if (!editor.toolbars || !editor.toolbars.length) {
17217 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17220 // for (var i =0 ; i < editor.toolbars.length;i++) {
17221 // editor.toolbars[i] = Roo.factory(
17222 // typeof(editor.toolbars[i]) == 'string' ?
17223 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17224 // Roo.bootstrap.HtmlEditor);
17225 // editor.toolbars[i].init(editor);
17231 onRender : function(ct, position)
17233 // Roo.log("Call onRender: " + this.xtype);
17235 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17237 this.wrap = this.inputEl().wrap({
17238 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17241 this.editorcore.onRender(ct, position);
17243 if (this.resizable) {
17244 this.resizeEl = new Roo.Resizable(this.wrap, {
17248 minHeight : this.height,
17249 height: this.height,
17250 handles : this.resizable,
17253 resize : function(r, w, h) {
17254 _t.onResize(w,h); // -something
17260 this.createToolbar(this);
17263 if(!this.width && this.resizable){
17264 this.setSize(this.wrap.getSize());
17266 if (this.resizeEl) {
17267 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17268 // should trigger onReize..
17274 onResize : function(w, h)
17276 Roo.log('resize: ' +w + ',' + h );
17277 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17281 if(this.inputEl() ){
17282 if(typeof w == 'number'){
17283 var aw = w - this.wrap.getFrameWidth('lr');
17284 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17287 if(typeof h == 'number'){
17288 var tbh = -11; // fixme it needs to tool bar size!
17289 for (var i =0; i < this.toolbars.length;i++) {
17290 // fixme - ask toolbars for heights?
17291 tbh += this.toolbars[i].el.getHeight();
17292 //if (this.toolbars[i].footer) {
17293 // tbh += this.toolbars[i].footer.el.getHeight();
17301 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17302 ah -= 5; // knock a few pixes off for look..
17303 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17307 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17308 this.editorcore.onResize(ew,eh);
17313 * Toggles the editor between standard and source edit mode.
17314 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17316 toggleSourceEdit : function(sourceEditMode)
17318 this.editorcore.toggleSourceEdit(sourceEditMode);
17320 if(this.editorcore.sourceEditMode){
17321 Roo.log('editor - showing textarea');
17324 // Roo.log(this.syncValue());
17326 this.inputEl().removeClass(['hide', 'x-hidden']);
17327 this.inputEl().dom.removeAttribute('tabIndex');
17328 this.inputEl().focus();
17330 Roo.log('editor - hiding textarea');
17332 // Roo.log(this.pushValue());
17335 this.inputEl().addClass(['hide', 'x-hidden']);
17336 this.inputEl().dom.setAttribute('tabIndex', -1);
17337 //this.deferFocus();
17340 if(this.resizable){
17341 this.setSize(this.wrap.getSize());
17344 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17347 // private (for BoxComponent)
17348 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17350 // private (for BoxComponent)
17351 getResizeEl : function(){
17355 // private (for BoxComponent)
17356 getPositionEl : function(){
17361 initEvents : function(){
17362 this.originalValue = this.getValue();
17366 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17369 // markInvalid : Roo.emptyFn,
17371 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17374 // clearInvalid : Roo.emptyFn,
17376 setValue : function(v){
17377 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17378 this.editorcore.pushValue();
17383 deferFocus : function(){
17384 this.focus.defer(10, this);
17388 focus : function(){
17389 this.editorcore.focus();
17395 onDestroy : function(){
17401 for (var i =0; i < this.toolbars.length;i++) {
17402 // fixme - ask toolbars for heights?
17403 this.toolbars[i].onDestroy();
17406 this.wrap.dom.innerHTML = '';
17407 this.wrap.remove();
17412 onFirstFocus : function(){
17413 //Roo.log("onFirstFocus");
17414 this.editorcore.onFirstFocus();
17415 for (var i =0; i < this.toolbars.length;i++) {
17416 this.toolbars[i].onFirstFocus();
17422 syncValue : function()
17424 this.editorcore.syncValue();
17427 pushValue : function()
17429 this.editorcore.pushValue();
17433 // hide stuff that is not compatible
17447 * @event specialkey
17451 * @cfg {String} fieldClass @hide
17454 * @cfg {String} focusClass @hide
17457 * @cfg {String} autoCreate @hide
17460 * @cfg {String} inputType @hide
17463 * @cfg {String} invalidClass @hide
17466 * @cfg {String} invalidText @hide
17469 * @cfg {String} msgFx @hide
17472 * @cfg {String} validateOnBlur @hide
17481 Roo.namespace('Roo.bootstrap.htmleditor');
17483 * @class Roo.bootstrap.HtmlEditorToolbar1
17488 new Roo.bootstrap.HtmlEditor({
17491 new Roo.bootstrap.HtmlEditorToolbar1({
17492 disable : { fonts: 1 , format: 1, ..., ... , ...],
17498 * @cfg {Object} disable List of elements to disable..
17499 * @cfg {Array} btns List of additional buttons.
17503 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17506 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17509 Roo.apply(this, config);
17511 // default disabled, based on 'good practice'..
17512 this.disable = this.disable || {};
17513 Roo.applyIf(this.disable, {
17516 specialElements : true
17518 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17520 this.editor = config.editor;
17521 this.editorcore = config.editor.editorcore;
17523 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17525 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17526 // dont call parent... till later.
17528 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17533 editorcore : false,
17538 "h1","h2","h3","h4","h5","h6",
17540 "abbr", "acronym", "address", "cite", "samp", "var",
17544 onRender : function(ct, position)
17546 // Roo.log("Call onRender: " + this.xtype);
17548 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17550 this.el.dom.style.marginBottom = '0';
17552 var editorcore = this.editorcore;
17553 var editor= this.editor;
17556 var btn = function(id,cmd , toggle, handler){
17558 var event = toggle ? 'toggle' : 'click';
17563 xns: Roo.bootstrap,
17566 enableToggle:toggle !== false,
17568 pressed : toggle ? false : null,
17571 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17572 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17581 xns: Roo.bootstrap,
17582 glyphicon : 'font',
17586 xns: Roo.bootstrap,
17590 Roo.each(this.formats, function(f) {
17591 style.menu.items.push({
17593 xns: Roo.bootstrap,
17594 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17599 editorcore.insertTag(this.tagname);
17606 children.push(style);
17609 btn('bold',false,true);
17610 btn('italic',false,true);
17611 btn('align-left', 'justifyleft',true);
17612 btn('align-center', 'justifycenter',true);
17613 btn('align-right' , 'justifyright',true);
17614 btn('link', false, false, function(btn) {
17615 //Roo.log("create link?");
17616 var url = prompt(this.createLinkText, this.defaultLinkValue);
17617 if(url && url != 'http:/'+'/'){
17618 this.editorcore.relayCmd('createlink', url);
17621 btn('list','insertunorderedlist',true);
17622 btn('pencil', false,true, function(btn){
17625 this.toggleSourceEdit(btn.pressed);
17631 xns: Roo.bootstrap,
17636 xns: Roo.bootstrap,
17641 cog.menu.items.push({
17643 xns: Roo.bootstrap,
17644 html : Clean styles,
17649 editorcore.insertTag(this.tagname);
17658 this.xtype = 'NavSimplebar';
17660 for(var i=0;i< children.length;i++) {
17662 this.buttons.add(this.addxtypeChild(children[i]));
17666 editor.on('editorevent', this.updateToolbar, this);
17668 onBtnClick : function(id)
17670 this.editorcore.relayCmd(id);
17671 this.editorcore.focus();
17675 * Protected method that will not generally be called directly. It triggers
17676 * a toolbar update by reading the markup state of the current selection in the editor.
17678 updateToolbar: function(){
17680 if(!this.editorcore.activated){
17681 this.editor.onFirstFocus(); // is this neeed?
17685 var btns = this.buttons;
17686 var doc = this.editorcore.doc;
17687 btns.get('bold').setActive(doc.queryCommandState('bold'));
17688 btns.get('italic').setActive(doc.queryCommandState('italic'));
17689 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17691 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17692 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17693 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17695 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17696 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17699 var ans = this.editorcore.getAllAncestors();
17700 if (this.formatCombo) {
17703 var store = this.formatCombo.store;
17704 this.formatCombo.setValue("");
17705 for (var i =0; i < ans.length;i++) {
17706 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17708 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17716 // hides menus... - so this cant be on a menu...
17717 Roo.bootstrap.MenuMgr.hideAll();
17719 Roo.bootstrap.MenuMgr.hideAll();
17720 //this.editorsyncValue();
17722 onFirstFocus: function() {
17723 this.buttons.each(function(item){
17727 toggleSourceEdit : function(sourceEditMode){
17730 if(sourceEditMode){
17731 Roo.log("disabling buttons");
17732 this.buttons.each( function(item){
17733 if(item.cmd != 'pencil'){
17739 Roo.log("enabling buttons");
17740 if(this.editorcore.initialized){
17741 this.buttons.each( function(item){
17747 Roo.log("calling toggole on editor");
17748 // tell the editor that it's been pressed..
17749 this.editor.toggleSourceEdit(sourceEditMode);
17759 * @class Roo.bootstrap.Table.AbstractSelectionModel
17760 * @extends Roo.util.Observable
17761 * Abstract base class for grid SelectionModels. It provides the interface that should be
17762 * implemented by descendant classes. This class should not be directly instantiated.
17765 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17766 this.locked = false;
17767 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17771 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17772 /** @ignore Called by the grid automatically. Do not call directly. */
17773 init : function(grid){
17779 * Locks the selections.
17782 this.locked = true;
17786 * Unlocks the selections.
17788 unlock : function(){
17789 this.locked = false;
17793 * Returns true if the selections are locked.
17794 * @return {Boolean}
17796 isLocked : function(){
17797 return this.locked;
17801 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17802 * @class Roo.bootstrap.Table.RowSelectionModel
17803 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17804 * It supports multiple selections and keyboard selection/navigation.
17806 * @param {Object} config
17809 Roo.bootstrap.Table.RowSelectionModel = function(config){
17810 Roo.apply(this, config);
17811 this.selections = new Roo.util.MixedCollection(false, function(o){
17816 this.lastActive = false;
17820 * @event selectionchange
17821 * Fires when the selection changes
17822 * @param {SelectionModel} this
17824 "selectionchange" : true,
17826 * @event afterselectionchange
17827 * Fires after the selection changes (eg. by key press or clicking)
17828 * @param {SelectionModel} this
17830 "afterselectionchange" : true,
17832 * @event beforerowselect
17833 * Fires when a row is selected being selected, return false to cancel.
17834 * @param {SelectionModel} this
17835 * @param {Number} rowIndex The selected index
17836 * @param {Boolean} keepExisting False if other selections will be cleared
17838 "beforerowselect" : true,
17841 * Fires when a row is selected.
17842 * @param {SelectionModel} this
17843 * @param {Number} rowIndex The selected index
17844 * @param {Roo.data.Record} r The record
17846 "rowselect" : true,
17848 * @event rowdeselect
17849 * Fires when a row is deselected.
17850 * @param {SelectionModel} this
17851 * @param {Number} rowIndex The selected index
17853 "rowdeselect" : true
17855 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17856 this.locked = false;
17859 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17861 * @cfg {Boolean} singleSelect
17862 * True to allow selection of only one row at a time (defaults to false)
17864 singleSelect : false,
17867 initEvents : function(){
17869 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17870 this.grid.on("mousedown", this.handleMouseDown, this);
17871 }else{ // allow click to work like normal
17872 this.grid.on("rowclick", this.handleDragableRowClick, this);
17875 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17876 "up" : function(e){
17878 this.selectPrevious(e.shiftKey);
17879 }else if(this.last !== false && this.lastActive !== false){
17880 var last = this.last;
17881 this.selectRange(this.last, this.lastActive-1);
17882 this.grid.getView().focusRow(this.lastActive);
17883 if(last !== false){
17887 this.selectFirstRow();
17889 this.fireEvent("afterselectionchange", this);
17891 "down" : function(e){
17893 this.selectNext(e.shiftKey);
17894 }else if(this.last !== false && this.lastActive !== false){
17895 var last = this.last;
17896 this.selectRange(this.last, this.lastActive+1);
17897 this.grid.getView().focusRow(this.lastActive);
17898 if(last !== false){
17902 this.selectFirstRow();
17904 this.fireEvent("afterselectionchange", this);
17909 var view = this.grid.view;
17910 view.on("refresh", this.onRefresh, this);
17911 view.on("rowupdated", this.onRowUpdated, this);
17912 view.on("rowremoved", this.onRemove, this);
17916 onRefresh : function(){
17917 var ds = this.grid.dataSource, i, v = this.grid.view;
17918 var s = this.selections;
17919 s.each(function(r){
17920 if((i = ds.indexOfId(r.id)) != -1){
17929 onRemove : function(v, index, r){
17930 this.selections.remove(r);
17934 onRowUpdated : function(v, index, r){
17935 if(this.isSelected(r)){
17936 v.onRowSelect(index);
17942 * @param {Array} records The records to select
17943 * @param {Boolean} keepExisting (optional) True to keep existing selections
17945 selectRecords : function(records, keepExisting){
17947 this.clearSelections();
17949 var ds = this.grid.dataSource;
17950 for(var i = 0, len = records.length; i < len; i++){
17951 this.selectRow(ds.indexOf(records[i]), true);
17956 * Gets the number of selected rows.
17959 getCount : function(){
17960 return this.selections.length;
17964 * Selects the first row in the grid.
17966 selectFirstRow : function(){
17971 * Select the last row.
17972 * @param {Boolean} keepExisting (optional) True to keep existing selections
17974 selectLastRow : function(keepExisting){
17975 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17979 * Selects the row immediately following the last selected row.
17980 * @param {Boolean} keepExisting (optional) True to keep existing selections
17982 selectNext : function(keepExisting){
17983 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17984 this.selectRow(this.last+1, keepExisting);
17985 this.grid.getView().focusRow(this.last);
17990 * Selects the row that precedes the last selected row.
17991 * @param {Boolean} keepExisting (optional) True to keep existing selections
17993 selectPrevious : function(keepExisting){
17995 this.selectRow(this.last-1, keepExisting);
17996 this.grid.getView().focusRow(this.last);
18001 * Returns the selected records
18002 * @return {Array} Array of selected records
18004 getSelections : function(){
18005 return [].concat(this.selections.items);
18009 * Returns the first selected record.
18012 getSelected : function(){
18013 return this.selections.itemAt(0);
18018 * Clears all selections.
18020 clearSelections : function(fast){
18021 if(this.locked) return;
18023 var ds = this.grid.dataSource;
18024 var s = this.selections;
18025 s.each(function(r){
18026 this.deselectRow(ds.indexOfId(r.id));
18030 this.selections.clear();
18037 * Selects all rows.
18039 selectAll : function(){
18040 if(this.locked) return;
18041 this.selections.clear();
18042 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18043 this.selectRow(i, true);
18048 * Returns True if there is a selection.
18049 * @return {Boolean}
18051 hasSelection : function(){
18052 return this.selections.length > 0;
18056 * Returns True if the specified row is selected.
18057 * @param {Number/Record} record The record or index of the record to check
18058 * @return {Boolean}
18060 isSelected : function(index){
18061 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18062 return (r && this.selections.key(r.id) ? true : false);
18066 * Returns True if the specified record id is selected.
18067 * @param {String} id The id of record to check
18068 * @return {Boolean}
18070 isIdSelected : function(id){
18071 return (this.selections.key(id) ? true : false);
18075 handleMouseDown : function(e, t){
18076 var view = this.grid.getView(), rowIndex;
18077 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18080 if(e.shiftKey && this.last !== false){
18081 var last = this.last;
18082 this.selectRange(last, rowIndex, e.ctrlKey);
18083 this.last = last; // reset the last
18084 view.focusRow(rowIndex);
18086 var isSelected = this.isSelected(rowIndex);
18087 if(e.button !== 0 && isSelected){
18088 view.focusRow(rowIndex);
18089 }else if(e.ctrlKey && isSelected){
18090 this.deselectRow(rowIndex);
18091 }else if(!isSelected){
18092 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18093 view.focusRow(rowIndex);
18096 this.fireEvent("afterselectionchange", this);
18099 handleDragableRowClick : function(grid, rowIndex, e)
18101 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18102 this.selectRow(rowIndex, false);
18103 grid.view.focusRow(rowIndex);
18104 this.fireEvent("afterselectionchange", this);
18109 * Selects multiple rows.
18110 * @param {Array} rows Array of the indexes of the row to select
18111 * @param {Boolean} keepExisting (optional) True to keep existing selections
18113 selectRows : function(rows, keepExisting){
18115 this.clearSelections();
18117 for(var i = 0, len = rows.length; i < len; i++){
18118 this.selectRow(rows[i], true);
18123 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18124 * @param {Number} startRow The index of the first row in the range
18125 * @param {Number} endRow The index of the last row in the range
18126 * @param {Boolean} keepExisting (optional) True to retain existing selections
18128 selectRange : function(startRow, endRow, keepExisting){
18129 if(this.locked) return;
18131 this.clearSelections();
18133 if(startRow <= endRow){
18134 for(var i = startRow; i <= endRow; i++){
18135 this.selectRow(i, true);
18138 for(var i = startRow; i >= endRow; i--){
18139 this.selectRow(i, true);
18145 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18146 * @param {Number} startRow The index of the first row in the range
18147 * @param {Number} endRow The index of the last row in the range
18149 deselectRange : function(startRow, endRow, preventViewNotify){
18150 if(this.locked) return;
18151 for(var i = startRow; i <= endRow; i++){
18152 this.deselectRow(i, preventViewNotify);
18158 * @param {Number} row The index of the row to select
18159 * @param {Boolean} keepExisting (optional) True to keep existing selections
18161 selectRow : function(index, keepExisting, preventViewNotify){
18162 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18163 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18164 if(!keepExisting || this.singleSelect){
18165 this.clearSelections();
18167 var r = this.grid.dataSource.getAt(index);
18168 this.selections.add(r);
18169 this.last = this.lastActive = index;
18170 if(!preventViewNotify){
18171 this.grid.getView().onRowSelect(index);
18173 this.fireEvent("rowselect", this, index, r);
18174 this.fireEvent("selectionchange", this);
18180 * @param {Number} row The index of the row to deselect
18182 deselectRow : function(index, preventViewNotify){
18183 if(this.locked) return;
18184 if(this.last == index){
18187 if(this.lastActive == index){
18188 this.lastActive = false;
18190 var r = this.grid.dataSource.getAt(index);
18191 this.selections.remove(r);
18192 if(!preventViewNotify){
18193 this.grid.getView().onRowDeselect(index);
18195 this.fireEvent("rowdeselect", this, index);
18196 this.fireEvent("selectionchange", this);
18200 restoreLast : function(){
18202 this.last = this._last;
18207 acceptsNav : function(row, col, cm){
18208 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18212 onEditorKey : function(field, e){
18213 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18218 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18220 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18222 }else if(k == e.ENTER && !e.ctrlKey){
18226 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18228 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18230 }else if(k == e.ESC){
18234 g.startEditing(newCell[0], newCell[1]);
18239 * Ext JS Library 1.1.1
18240 * Copyright(c) 2006-2007, Ext JS, LLC.
18242 * Originally Released Under LGPL - original licence link has changed is not relivant.
18245 * <script type="text/javascript">
18249 * @class Roo.bootstrap.PagingToolbar
18251 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18253 * Create a new PagingToolbar
18254 * @param {Object} config The config object
18256 Roo.bootstrap.PagingToolbar = function(config)
18258 // old args format still supported... - xtype is prefered..
18259 // created from xtype...
18260 var ds = config.dataSource;
18261 this.toolbarItems = [];
18262 if (config.items) {
18263 this.toolbarItems = config.items;
18264 // config.items = [];
18267 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18274 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18278 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18280 * @cfg {Roo.data.Store} dataSource
18281 * The underlying data store providing the paged data
18284 * @cfg {String/HTMLElement/Element} container
18285 * container The id or element that will contain the toolbar
18288 * @cfg {Boolean} displayInfo
18289 * True to display the displayMsg (defaults to false)
18292 * @cfg {Number} pageSize
18293 * The number of records to display per page (defaults to 20)
18297 * @cfg {String} displayMsg
18298 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18300 displayMsg : 'Displaying {0} - {1} of {2}',
18302 * @cfg {String} emptyMsg
18303 * The message to display when no records are found (defaults to "No data to display")
18305 emptyMsg : 'No data to display',
18307 * Customizable piece of the default paging text (defaults to "Page")
18310 beforePageText : "Page",
18312 * Customizable piece of the default paging text (defaults to "of %0")
18315 afterPageText : "of {0}",
18317 * Customizable piece of the default paging text (defaults to "First Page")
18320 firstText : "First Page",
18322 * Customizable piece of the default paging text (defaults to "Previous Page")
18325 prevText : "Previous Page",
18327 * Customizable piece of the default paging text (defaults to "Next Page")
18330 nextText : "Next Page",
18332 * Customizable piece of the default paging text (defaults to "Last Page")
18335 lastText : "Last Page",
18337 * Customizable piece of the default paging text (defaults to "Refresh")
18340 refreshText : "Refresh",
18344 onRender : function(ct, position)
18346 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18347 this.navgroup.parentId = this.id;
18348 this.navgroup.onRender(this.el, null);
18349 // add the buttons to the navgroup
18351 if(this.displayInfo){
18352 Roo.log(this.el.select('ul.navbar-nav',true).first());
18353 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18354 this.displayEl = this.el.select('.x-paging-info', true).first();
18355 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18356 // this.displayEl = navel.el.select('span',true).first();
18362 Roo.each(_this.buttons, function(e){
18363 Roo.factory(e).onRender(_this.el, null);
18367 Roo.each(_this.toolbarItems, function(e) {
18368 _this.navgroup.addItem(e);
18371 this.first = this.navgroup.addItem({
18372 tooltip: this.firstText,
18374 icon : 'fa fa-backward',
18376 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18379 this.prev = this.navgroup.addItem({
18380 tooltip: this.prevText,
18382 icon : 'fa fa-step-backward',
18384 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18386 //this.addSeparator();
18389 var field = this.navgroup.addItem( {
18391 cls : 'x-paging-position',
18393 html : this.beforePageText +
18394 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18395 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18398 this.field = field.el.select('input', true).first();
18399 this.field.on("keydown", this.onPagingKeydown, this);
18400 this.field.on("focus", function(){this.dom.select();});
18403 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18404 //this.field.setHeight(18);
18405 //this.addSeparator();
18406 this.next = this.navgroup.addItem({
18407 tooltip: this.nextText,
18409 html : ' <i class="fa fa-step-forward">',
18411 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18413 this.last = this.navgroup.addItem({
18414 tooltip: this.lastText,
18415 icon : 'fa fa-forward',
18418 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18420 //this.addSeparator();
18421 this.loading = this.navgroup.addItem({
18422 tooltip: this.refreshText,
18423 icon: 'fa fa-refresh',
18425 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18431 updateInfo : function(){
18432 if(this.displayEl){
18433 var count = this.ds.getCount();
18434 var msg = count == 0 ?
18438 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18440 this.displayEl.update(msg);
18445 onLoad : function(ds, r, o){
18446 this.cursor = o.params ? o.params.start : 0;
18447 var d = this.getPageData(),
18451 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18452 this.field.dom.value = ap;
18453 this.first.setDisabled(ap == 1);
18454 this.prev.setDisabled(ap == 1);
18455 this.next.setDisabled(ap == ps);
18456 this.last.setDisabled(ap == ps);
18457 this.loading.enable();
18462 getPageData : function(){
18463 var total = this.ds.getTotalCount();
18466 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18467 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18472 onLoadError : function(){
18473 this.loading.enable();
18477 onPagingKeydown : function(e){
18478 var k = e.getKey();
18479 var d = this.getPageData();
18481 var v = this.field.dom.value, pageNum;
18482 if(!v || isNaN(pageNum = parseInt(v, 10))){
18483 this.field.dom.value = d.activePage;
18486 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18487 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18490 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
18492 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18493 this.field.dom.value = pageNum;
18494 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18497 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18499 var v = this.field.dom.value, pageNum;
18500 var increment = (e.shiftKey) ? 10 : 1;
18501 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18503 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18504 this.field.dom.value = d.activePage;
18507 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18509 this.field.dom.value = parseInt(v, 10) + increment;
18510 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18511 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18518 beforeLoad : function(){
18520 this.loading.disable();
18525 onClick : function(which){
18532 ds.load({params:{start: 0, limit: this.pageSize}});
18535 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18538 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18541 var total = ds.getTotalCount();
18542 var extra = total % this.pageSize;
18543 var lastStart = extra ? (total - extra) : total-this.pageSize;
18544 ds.load({params:{start: lastStart, limit: this.pageSize}});
18547 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18553 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18554 * @param {Roo.data.Store} store The data store to unbind
18556 unbind : function(ds){
18557 ds.un("beforeload", this.beforeLoad, this);
18558 ds.un("load", this.onLoad, this);
18559 ds.un("loadexception", this.onLoadError, this);
18560 ds.un("remove", this.updateInfo, this);
18561 ds.un("add", this.updateInfo, this);
18562 this.ds = undefined;
18566 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18567 * @param {Roo.data.Store} store The data store to bind
18569 bind : function(ds){
18570 ds.on("beforeload", this.beforeLoad, this);
18571 ds.on("load", this.onLoad, this);
18572 ds.on("loadexception", this.onLoadError, this);
18573 ds.on("remove", this.updateInfo, this);
18574 ds.on("add", this.updateInfo, this);
18585 * @class Roo.bootstrap.MessageBar
18586 * @extends Roo.bootstrap.Component
18587 * Bootstrap MessageBar class
18588 * @cfg {String} html contents of the MessageBar
18589 * @cfg {String} weight (info | success | warning | danger) default info
18590 * @cfg {String} beforeClass insert the bar before the given class
18591 * @cfg {Boolean} closable (true | false) default false
18592 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18595 * Create a new Element
18596 * @param {Object} config The config object
18599 Roo.bootstrap.MessageBar = function(config){
18600 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18603 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18609 beforeClass: 'bootstrap-sticky-wrap',
18611 getAutoCreate : function(){
18615 cls: 'alert alert-dismissable alert-' + this.weight,
18620 html: this.html || ''
18626 cfg.cls += ' alert-messages-fixed';
18640 onRender : function(ct, position)
18642 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18645 var cfg = Roo.apply({}, this.getAutoCreate());
18649 cfg.cls += ' ' + this.cls;
18652 cfg.style = this.style;
18654 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18656 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18659 this.el.select('>button.close').on('click', this.hide, this);
18665 if (!this.rendered) {
18671 this.fireEvent('show', this);
18677 if (!this.rendered) {
18683 this.fireEvent('hide', this);
18686 update : function()
18688 // var e = this.el.dom.firstChild;
18690 // if(this.closable){
18691 // e = e.nextSibling;
18694 // e.data = this.html || '';
18696 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18712 * @class Roo.bootstrap.Graph
18713 * @extends Roo.bootstrap.Component
18714 * Bootstrap Graph class
18718 @cfg {String} graphtype bar | vbar | pie
18719 @cfg {number} g_x coodinator | centre x (pie)
18720 @cfg {number} g_y coodinator | centre y (pie)
18721 @cfg {number} g_r radius (pie)
18722 @cfg {number} g_height height of the chart (respected by all elements in the set)
18723 @cfg {number} g_width width of the chart (respected by all elements in the set)
18724 @cfg {Object} title The title of the chart
18727 -opts (object) options for the chart
18729 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18730 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18732 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
18733 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18735 o stretch (boolean)
18737 -opts (object) options for the pie
18740 o startAngle (number)
18741 o endAngle (number)
18745 * Create a new Input
18746 * @param {Object} config The config object
18749 Roo.bootstrap.Graph = function(config){
18750 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18756 * The img click event for the img.
18757 * @param {Roo.EventObject} e
18763 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18774 //g_colors: this.colors,
18781 getAutoCreate : function(){
18792 onRender : function(ct,position){
18793 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18794 this.raphael = Raphael(this.el.dom);
18796 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18797 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18798 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18799 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18801 r.text(160, 10, "Single Series Chart").attr(txtattr);
18802 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18803 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18804 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18806 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18807 r.barchart(330, 10, 300, 220, data1);
18808 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18809 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18812 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18813 // r.barchart(30, 30, 560, 250, xdata, {
18814 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18815 // axis : "0 0 1 1",
18816 // axisxlabels : xdata
18817 // //yvalues : cols,
18820 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18822 // this.load(null,xdata,{
18823 // axis : "0 0 1 1",
18824 // axisxlabels : xdata
18829 load : function(graphtype,xdata,opts){
18830 this.raphael.clear();
18832 graphtype = this.graphtype;
18837 var r = this.raphael,
18838 fin = function () {
18839 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18841 fout = function () {
18842 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18844 pfin = function() {
18845 this.sector.stop();
18846 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18849 this.label[0].stop();
18850 this.label[0].attr({ r: 7.5 });
18851 this.label[1].attr({ "font-weight": 800 });
18854 pfout = function() {
18855 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18858 this.label[0].animate({ r: 5 }, 500, "bounce");
18859 this.label[1].attr({ "font-weight": 400 });
18865 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18868 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18871 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18872 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18874 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18881 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18886 setTitle: function(o)
18891 initEvents: function() {
18894 this.el.on('click', this.onClick, this);
18898 onClick : function(e)
18900 Roo.log('img onclick');
18901 this.fireEvent('click', this, e);
18913 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18916 * @class Roo.bootstrap.dash.NumberBox
18917 * @extends Roo.bootstrap.Component
18918 * Bootstrap NumberBox class
18919 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18920 * @cfg {String} headline Box headline
18921 * @cfg {String} content Box content
18922 * @cfg {String} icon Box icon
18923 * @cfg {String} footer Footer text
18924 * @cfg {String} fhref Footer href
18927 * Create a new NumberBox
18928 * @param {Object} config The config object
18932 Roo.bootstrap.dash.NumberBox = function(config){
18933 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18937 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
18947 getAutoCreate : function(){
18951 cls : 'small-box bg-' + this.bgcolor,
18959 cls : 'roo-headline',
18960 html : this.headline
18964 cls : 'roo-content',
18965 html : this.content
18979 cls : 'ion ' + this.icon
18988 cls : 'small-box-footer',
18989 href : this.fhref || '#',
18993 cfg.cn.push(footer);
19000 onRender : function(ct,position){
19001 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19008 setHeadline: function (value)
19010 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19013 setFooter: function (value, href)
19015 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19018 this.el.select('a.small-box-footer',true).first().attr('href', href);
19023 setContent: function (value)
19025 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19028 initEvents: function()
19042 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19045 * @class Roo.bootstrap.dash.TabBox
19046 * @extends Roo.bootstrap.Component
19047 * Bootstrap TabBox class
19048 * @cfg {String} title Title of the TabBox
19049 * @cfg {String} icon Icon of the TabBox
19052 * Create a new TabBox
19053 * @param {Object} config The config object
19057 Roo.bootstrap.dash.TabBox = function(config){
19058 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19062 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19067 getChildContainer : function()
19069 return this.el.select('.tab-content', true).first();
19072 getAutoCreate : function(){
19076 cls: 'pull-left header',
19084 cls: 'fa ' + this.icon
19091 cls: 'nav-tabs-custom',
19095 cls: 'nav nav-tabs pull-right',
19102 cls: 'tab-content no-padding',
19111 setTitle : function(value)
19113 this.el.select('.header', true).first().dom.innerHTML = value;
19125 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19127 * @class Roo.bootstrap.TabPane
19128 * @extends Roo.bootstrap.Component
19129 * Bootstrap TabPane class
19130 * @cfg {Boolean} active (false | true) Default false
19134 * Create a new TabPane
19135 * @param {Object} config The config object
19138 Roo.bootstrap.dash.TabPane = function(config){
19139 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19143 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19147 // getBox : function()
19149 // return this.el.findParent('.nav-tabs-custom', false, true);
19152 getAutoCreate : function()
19160 cfg.cls += ' active';
19178 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19181 * @class Roo.bootstrap.menu.Menu
19182 * @extends Roo.bootstrap.Component
19183 * Bootstrap Menu class - container for Menu
19184 * @cfg {String} html Text of the menu
19185 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19186 * @cfg {String} icon Font awesome icon
19187 * @cfg {String} pos Menu align to (top | bottom) default bottom
19191 * Create a new Menu
19192 * @param {Object} config The config object
19196 Roo.bootstrap.menu.Menu = function(config){
19197 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19201 * @event beforeshow
19202 * Fires before this menu is displayed
19203 * @param {Roo.bootstrap.menu.Menu} this
19207 * @event beforehide
19208 * Fires before this menu is hidden
19209 * @param {Roo.bootstrap.menu.Menu} this
19214 * Fires after this menu is displayed
19215 * @param {Roo.bootstrap.menu.Menu} this
19220 * Fires after this menu is hidden
19221 * @param {Roo.bootstrap.menu.Menu} this
19226 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19227 * @param {Roo.bootstrap.menu.Menu} this
19228 * @param {Roo.EventObject} e
19235 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19239 weight : 'default',
19244 getChildContainer : function() {
19245 if(this.isSubMenu){
19249 return this.el.select('ul.dropdown-menu', true).first();
19252 getAutoCreate : function()
19257 cls : 'roo-menu-text',
19265 cls : 'fa ' + this.icon
19276 cls : 'dropdown-button btn btn-' + this.weight,
19281 cls : 'dropdown-toggle btn btn-' + this.weight,
19291 cls : 'dropdown-menu'
19297 if(this.pos == 'top'){
19298 cfg.cls += ' dropup';
19301 if(this.isSubMenu){
19304 cls : 'dropdown-menu'
19311 onRender : function(ct, position)
19313 this.isSubMenu = ct.hasClass('dropdown-submenu');
19315 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19318 initEvents : function()
19320 if(this.isSubMenu){
19324 this.hidden = true;
19326 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19327 this.triggerEl.on('click', this.onTriggerPress, this);
19329 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19330 this.buttonEl.on('click', this.onClick, this);
19336 if(this.isSubMenu){
19340 return this.el.select('ul.dropdown-menu', true).first();
19343 onClick : function(e)
19345 this.fireEvent("click", this, e);
19348 onTriggerPress : function(e)
19350 if (this.isVisible()) {
19357 isVisible : function(){
19358 return !this.hidden;
19363 this.fireEvent("beforeshow", this);
19365 this.hidden = false;
19366 this.el.addClass('open');
19368 Roo.get(document).on("mouseup", this.onMouseUp, this);
19370 this.fireEvent("show", this);
19377 this.fireEvent("beforehide", this);
19379 this.hidden = true;
19380 this.el.removeClass('open');
19382 Roo.get(document).un("mouseup", this.onMouseUp);
19384 this.fireEvent("hide", this);
19387 onMouseUp : function()
19401 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19404 * @class Roo.bootstrap.menu.Item
19405 * @extends Roo.bootstrap.Component
19406 * Bootstrap MenuItem class
19407 * @cfg {Boolean} submenu (true | false) default false
19408 * @cfg {String} html text of the item
19409 * @cfg {String} href the link
19410 * @cfg {Boolean} disable (true | false) default false
19411 * @cfg {Boolean} preventDefault (true | false) default true
19412 * @cfg {String} icon Font awesome icon
19413 * @cfg {String} pos Submenu align to (left | right) default right
19417 * Create a new Item
19418 * @param {Object} config The config object
19422 Roo.bootstrap.menu.Item = function(config){
19423 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19427 * Fires when the mouse is hovering over this menu
19428 * @param {Roo.bootstrap.menu.Item} this
19429 * @param {Roo.EventObject} e
19434 * Fires when the mouse exits this menu
19435 * @param {Roo.bootstrap.menu.Item} this
19436 * @param {Roo.EventObject} e
19442 * The raw click event for the entire grid.
19443 * @param {Roo.EventObject} e
19449 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19454 preventDefault: true,
19459 getAutoCreate : function()
19464 cls : 'roo-menu-item-text',
19472 cls : 'fa ' + this.icon
19481 href : this.href || '#',
19488 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19492 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19494 if(this.pos == 'left'){
19495 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19502 initEvents : function()
19504 this.el.on('mouseover', this.onMouseOver, this);
19505 this.el.on('mouseout', this.onMouseOut, this);
19507 this.el.select('a', true).first().on('click', this.onClick, this);
19511 onClick : function(e)
19513 if(this.preventDefault){
19514 e.preventDefault();
19517 this.fireEvent("click", this, e);
19520 onMouseOver : function(e)
19522 if(this.submenu && this.pos == 'left'){
19523 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19526 this.fireEvent("mouseover", this, e);
19529 onMouseOut : function(e)
19531 this.fireEvent("mouseout", this, e);
19543 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19546 * @class Roo.bootstrap.menu.Separator
19547 * @extends Roo.bootstrap.Component
19548 * Bootstrap Separator class
19551 * Create a new Separator
19552 * @param {Object} config The config object
19556 Roo.bootstrap.menu.Separator = function(config){
19557 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19560 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19562 getAutoCreate : function(){