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]());
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]());
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]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
284 Roo.bootstrap.Body = function(config){
285 Roo.bootstrap.Body.superclass.constructor.call(this, config);
286 this.el = Roo.get(document.body);
289 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
294 onRender : function(ct, position){
297 //this.el.addClass([this.fieldClass, this.cls]);
315 * @class Roo.bootstrap.ButtonGroup
316 * @extends Roo.bootstrap.Component
317 * Bootstrap ButtonGroup class
318 * @cfg {String} size lg | sm | xs (default empty normal)
319 * @cfg {String} align vertical | justified (default none)
320 * @cfg {String} direction up | down (default down)
321 * @cfg {Boolean} toolbar false | true
322 * @cfg {Boolean} btn true | false
327 * @param {Object} config The config object
330 Roo.bootstrap.ButtonGroup = function(config){
331 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
334 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
342 getAutoCreate : function(){
348 cfg.html = this.html || cfg.html;
359 if (['vertical','justified'].indexOf(this.align)!==-1) {
360 cfg.cls = 'btn-group-' + this.align;
362 if (this.align == 'justified') {
363 console.log(this.items);
367 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
368 cfg.cls += ' btn-group-' + this.size;
371 if (this.direction == 'up') {
372 cfg.cls += ' dropup' ;
388 * @class Roo.bootstrap.Button
389 * @extends Roo.bootstrap.Component
390 * Bootstrap Button class
391 * @cfg {String} html The button content
392 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
393 * @cfg {String} size empty | lg | sm | xs
394 * @cfg {String} tag empty | a | input | submit
395 * @cfg {String} href empty or href
396 * @cfg {Boolean} disabled false | true
397 * @cfg {Boolean} isClose false | true
398 * @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
399 * @cfg {String} badge text for badge
400 * @cfg {String} theme default (or empty) | glow
401 * @cfg {Boolean} inverse false | true
402 * @cfg {Boolean} toggle false | true
403 * @cfg {String} ontext text for on toggle state
404 * @cfg {String} offtext text for off toggle state
405 * @cfg {Boolean} defaulton true | false
406 * @cfg {Boolean} preventDefault (true | false) default true
407 * @cfg {Boolean} removeClass true | false remove the standard class..
408 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
411 * Create a new button
412 * @param {Object} config The config object
416 Roo.bootstrap.Button = function(config){
417 Roo.bootstrap.Button.superclass.constructor.call(this, config);
422 * When a butotn is pressed
423 * @param {Roo.EventObject} e
428 * After the button has been toggles
429 * @param {Roo.EventObject} e
430 * @param {boolean} pressed (also available as button.pressed)
436 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
454 preventDefault: true,
463 getAutoCreate : function(){
471 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
472 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
477 cfg.html = this.html || cfg.html;
479 if (this.toggle == true) {
482 cls: 'slider-frame roo-button',
487 'data-off-text':'OFF',
488 cls: 'slider-button',
494 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
495 cfg.cls += ' '+this.weight;
504 cfg["aria-hidden"] = true;
506 cfg.html = "×";
512 if (this.theme==='default') {
513 cfg.cls = 'btn roo-button';
515 //if (this.parentType != 'Navbar') {
516 this.weight = this.weight.length ? this.weight : 'default';
518 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
520 cfg.cls += ' btn-' + this.weight;
522 } else if (this.theme==='glow') {
525 cfg.cls = 'btn-glow roo-button';
527 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
529 cfg.cls += ' ' + this.weight;
535 this.cls += ' inverse';
540 cfg.cls += ' active';
544 cfg.disabled = 'disabled';
548 Roo.log('changing to ul' );
550 this.glyphicon = 'caret';
553 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
555 //gsRoo.log(this.parentType);
556 if (this.parentType === 'Navbar' && !this.parent().bar) {
557 Roo.log('changing to li?');
566 href : this.href || '#'
569 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
570 cfg.cls += ' dropdown';
577 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
579 if (this.glyphicon) {
580 cfg.html = ' ' + cfg.html;
585 cls: 'glyphicon glyphicon-' + this.glyphicon
595 // cfg.cls='btn roo-button';
599 var value = cfg.html;
604 cls: 'glyphicon glyphicon-' + this.glyphicon,
623 cfg.cls += ' dropdown';
624 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
627 if (cfg.tag !== 'a' && this.href !== '') {
628 throw "Tag must be a to set href.";
629 } else if (this.href.length > 0) {
630 cfg.href = this.href;
633 if(this.removeClass){
638 cfg.target = this.target;
643 initEvents: function() {
644 // Roo.log('init events?');
645 // Roo.log(this.el.dom);
646 if (this.el.hasClass('roo-button')) {
647 this.el.on('click', this.onClick, this);
649 this.el.select('.roo-button').on('click', this.onClick, this);
655 onClick : function(e)
661 Roo.log('button on click ');
662 if(this.preventDefault){
665 if (this.pressed === true || this.pressed === false) {
666 this.pressed = !this.pressed;
667 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
668 this.fireEvent('toggle', this, e, this.pressed);
672 this.fireEvent('click', this, e);
676 * Enables this button
680 this.disabled = false;
681 this.el.removeClass('disabled');
685 * Disable this button
689 this.disabled = true;
690 this.el.addClass('disabled');
693 * sets the active state on/off,
694 * @param {Boolean} state (optional) Force a particular state
696 setActive : function(v) {
698 this.el[v ? 'addClass' : 'removeClass']('active');
701 * toggles the current active state
703 toggleActive : function()
705 var active = this.el.hasClass('active');
706 this.setActive(!active);
723 * @class Roo.bootstrap.Column
724 * @extends Roo.bootstrap.Component
725 * Bootstrap Column class
726 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
727 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
728 * @cfg {Number} md colspan out of 12 for computer-sized screens
729 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
730 * @cfg {String} html content of column.
733 * Create a new Column
734 * @param {Object} config The config object
737 Roo.bootstrap.Column = function(config){
738 Roo.bootstrap.Column.superclass.constructor.call(this, config);
741 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
750 getAutoCreate : function(){
751 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
759 ['xs','sm','md','lg'].map(function(size){
760 if (settings[size]) {
761 cfg.cls += ' col-' + size + '-' + settings[size];
764 if (this.html.length) {
765 cfg.html = this.html;
784 * @class Roo.bootstrap.Container
785 * @extends Roo.bootstrap.Component
786 * Bootstrap Container class
787 * @cfg {Boolean} jumbotron is it a jumbotron element
788 * @cfg {String} html content of element
789 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
790 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
791 * @cfg {String} header content of header (for panel)
792 * @cfg {String} footer content of footer (for panel)
793 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
796 * Create a new Container
797 * @param {Object} config The config object
800 Roo.bootstrap.Container = function(config){
801 Roo.bootstrap.Container.superclass.constructor.call(this, config);
804 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
814 getChildContainer : function() {
820 if (this.panel.length) {
821 return this.el.select('.panel-body',true).first();
828 getAutoCreate : function(){
834 if (this.jumbotron) {
835 cfg.cls = 'jumbotron';
838 cfg.cls = this.cls + '';
841 if (this.sticky.length) {
843 var bd = Roo.get(document.body);
844 if (!bd.hasClass('bootstrap-sticky')) {
845 bd.addClass('bootstrap-sticky');
846 Roo.select('html',true).setStyle('height', '100%');
849 cfg.cls += 'bootstrap-sticky-' + this.sticky;
853 if (this.well.length) {
857 cfg.cls +=' well well-' +this.well;
867 if (this.panel.length) {
868 cfg.cls += ' panel panel-' + this.panel;
870 if (this.header.length) {
873 cls : 'panel-heading',
889 if (this.footer.length) {
891 cls : 'panel-footer',
899 body.html = this.html || cfg.html;
901 if (!cfg.cls.length) {
902 cfg.cls = 'container';
919 * @class Roo.bootstrap.Img
920 * @extends Roo.bootstrap.Component
921 * Bootstrap Img class
922 * @cfg {Boolean} imgResponsive false | true
923 * @cfg {String} border rounded | circle | thumbnail
924 * @cfg {String} src image source
925 * @cfg {String} alt image alternative text
926 * @cfg {String} href a tag href
927 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
931 * @param {Object} config The config object
934 Roo.bootstrap.Img = function(config){
935 Roo.bootstrap.Img.superclass.constructor.call(this, config);
941 * The img click event for the img.
942 * @param {Roo.EventObject} e
948 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
956 getAutoCreate : function(){
960 cls: 'img-responsive',
964 cfg.html = this.html || cfg.html;
966 cfg.src = this.src || cfg.src;
968 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
969 cfg.cls += ' img-' + this.border;
986 a.target = this.target;
992 return (this.href) ? a : cfg;
995 initEvents: function() {
998 this.el.on('click', this.onClick, this);
1002 onClick : function(e)
1004 Roo.log('img onclick');
1005 this.fireEvent('click', this, e);
1018 * @class Roo.bootstrap.Header
1019 * @extends Roo.bootstrap.Component
1020 * Bootstrap Header class
1021 * @cfg {String} html content of header
1022 * @cfg {Number} level (1|2|3|4|5|6) default 1
1025 * Create a new Header
1026 * @param {Object} config The config object
1030 Roo.bootstrap.Header = function(config){
1031 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1034 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1042 getAutoCreate : function(){
1045 tag: 'h' + (1 *this.level),
1046 html: this.html || 'fill in html'
1058 * Ext JS Library 1.1.1
1059 * Copyright(c) 2006-2007, Ext JS, LLC.
1061 * Originally Released Under LGPL - original licence link has changed is not relivant.
1064 * <script type="text/javascript">
1068 * @class Roo.bootstrap.MenuMgr
1069 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1072 Roo.bootstrap.MenuMgr = function(){
1073 var menus, active, groups = {}, attached = false, lastShow = new Date();
1075 // private - called when first menu is created
1078 active = new Roo.util.MixedCollection();
1079 Roo.get(document).addKeyListener(27, function(){
1080 if(active.length > 0){
1088 if(active && active.length > 0){
1089 var c = active.clone();
1099 if(active.length < 1){
1100 Roo.get(document).un("mouseup", onMouseDown);
1108 var last = active.last();
1109 lastShow = new Date();
1112 Roo.get(document).on("mouseup", onMouseDown);
1117 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1118 m.parentMenu.activeChild = m;
1119 }else if(last && last.isVisible()){
1120 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1125 function onBeforeHide(m){
1127 m.activeChild.hide();
1129 if(m.autoHideTimer){
1130 clearTimeout(m.autoHideTimer);
1131 delete m.autoHideTimer;
1136 function onBeforeShow(m){
1137 var pm = m.parentMenu;
1138 if(!pm && !m.allowOtherMenus){
1140 }else if(pm && pm.activeChild && active != m){
1141 pm.activeChild.hide();
1146 function onMouseDown(e){
1147 Roo.log("on MouseDown");
1148 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1156 function onBeforeCheck(mi, state){
1158 var g = groups[mi.group];
1159 for(var i = 0, l = g.length; i < l; i++){
1161 g[i].setChecked(false);
1170 * Hides all menus that are currently visible
1172 hideAll : function(){
1177 register : function(menu){
1181 menus[menu.id] = menu;
1182 menu.on("beforehide", onBeforeHide);
1183 menu.on("hide", onHide);
1184 menu.on("beforeshow", onBeforeShow);
1185 menu.on("show", onShow);
1187 if(g && menu.events["checkchange"]){
1191 groups[g].push(menu);
1192 menu.on("checkchange", onCheck);
1197 * Returns a {@link Roo.menu.Menu} object
1198 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1199 * be used to generate and return a new Menu instance.
1201 get : function(menu){
1202 if(typeof menu == "string"){ // menu id
1204 }else if(menu.events){ // menu instance
1207 /*else if(typeof menu.length == 'number'){ // array of menu items?
1208 return new Roo.bootstrap.Menu({items:menu});
1209 }else{ // otherwise, must be a config
1210 return new Roo.bootstrap.Menu(menu);
1217 unregister : function(menu){
1218 delete menus[menu.id];
1219 menu.un("beforehide", onBeforeHide);
1220 menu.un("hide", onHide);
1221 menu.un("beforeshow", onBeforeShow);
1222 menu.un("show", onShow);
1224 if(g && menu.events["checkchange"]){
1225 groups[g].remove(menu);
1226 menu.un("checkchange", onCheck);
1231 registerCheckable : function(menuItem){
1232 var g = menuItem.group;
1237 groups[g].push(menuItem);
1238 menuItem.on("beforecheckchange", onBeforeCheck);
1243 unregisterCheckable : function(menuItem){
1244 var g = menuItem.group;
1246 groups[g].remove(menuItem);
1247 menuItem.un("beforecheckchange", onBeforeCheck);
1259 * @class Roo.bootstrap.Menu
1260 * @extends Roo.bootstrap.Component
1261 * Bootstrap Menu class - container for MenuItems
1262 * @cfg {String} type type of menu
1266 * @param {Object} config The config object
1270 Roo.bootstrap.Menu = function(config){
1271 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1272 if (this.registerMenu) {
1273 Roo.bootstrap.MenuMgr.register(this);
1278 * Fires before this menu is displayed
1279 * @param {Roo.menu.Menu} this
1284 * Fires before this menu is hidden
1285 * @param {Roo.menu.Menu} this
1290 * Fires after this menu is displayed
1291 * @param {Roo.menu.Menu} this
1296 * Fires after this menu is hidden
1297 * @param {Roo.menu.Menu} this
1302 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1303 * @param {Roo.menu.Menu} this
1304 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1305 * @param {Roo.EventObject} e
1310 * Fires when the mouse is hovering over this menu
1311 * @param {Roo.menu.Menu} this
1312 * @param {Roo.EventObject} e
1313 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1318 * Fires when the mouse exits this menu
1319 * @param {Roo.menu.Menu} this
1320 * @param {Roo.EventObject} e
1321 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1326 * Fires when a menu item contained in this menu is clicked
1327 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1328 * @param {Roo.EventObject} e
1332 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1335 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1339 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1342 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1344 registerMenu : true,
1346 menuItems :false, // stores the menu items..
1352 getChildContainer : function() {
1356 getAutoCreate : function(){
1358 //if (['right'].indexOf(this.align)!==-1) {
1359 // cfg.cn[1].cls += ' pull-right'
1363 cls : 'dropdown-menu' ,
1364 style : 'z-index:1000'
1368 if (this.type === 'submenu') {
1369 cfg.cls = 'submenu active'
1374 initEvents : function() {
1376 // Roo.log("ADD event");
1377 // Roo.log(this.triggerEl.dom);
1378 this.triggerEl.on('click', this.onTriggerPress, this);
1379 this.triggerEl.addClass('dropdown-toggle');
1380 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1382 this.el.on("mouseover", this.onMouseOver, this);
1383 this.el.on("mouseout", this.onMouseOut, this);
1387 findTargetItem : function(e){
1388 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1392 //Roo.log(t); Roo.log(t.id);
1394 //Roo.log(this.menuitems);
1395 return this.menuitems.get(t.id);
1397 //return this.items.get(t.menuItemId);
1402 onClick : function(e){
1403 Roo.log("menu.onClick");
1404 var t = this.findTargetItem(e);
1410 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1411 if(t == this.activeItem && t.shouldDeactivate(e)){
1412 this.activeItem.deactivate();
1413 delete this.activeItem;
1417 this.setActiveItem(t, true);
1424 Roo.log('pass click event');
1428 this.fireEvent("click", this, t, e);
1432 onMouseOver : function(e){
1433 var t = this.findTargetItem(e);
1436 // if(t.canActivate && !t.disabled){
1437 // this.setActiveItem(t, true);
1441 this.fireEvent("mouseover", this, e, t);
1443 isVisible : function(){
1444 return !this.hidden;
1446 onMouseOut : function(e){
1447 var t = this.findTargetItem(e);
1450 // if(t == this.activeItem && t.shouldDeactivate(e)){
1451 // this.activeItem.deactivate();
1452 // delete this.activeItem;
1455 this.fireEvent("mouseout", this, e, t);
1460 * Displays this menu relative to another element
1461 * @param {String/HTMLElement/Roo.Element} element The element to align to
1462 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1463 * the element (defaults to this.defaultAlign)
1464 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1466 show : function(el, pos, parentMenu){
1467 this.parentMenu = parentMenu;
1471 this.fireEvent("beforeshow", this);
1472 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1475 * Displays this menu at a specific xy position
1476 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1477 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1479 showAt : function(xy, parentMenu, /* private: */_e){
1480 this.parentMenu = parentMenu;
1485 this.fireEvent("beforeshow", this);
1487 //xy = this.el.adjustForConstraints(xy);
1489 //this.el.setXY(xy);
1491 this.hideMenuItems();
1492 this.hidden = false;
1493 this.triggerEl.addClass('open');
1495 this.fireEvent("show", this);
1501 this.doFocus.defer(50, this);
1505 doFocus : function(){
1507 this.focusEl.focus();
1512 * Hides this menu and optionally all parent menus
1513 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1515 hide : function(deep){
1517 this.hideMenuItems();
1518 if(this.el && this.isVisible()){
1519 this.fireEvent("beforehide", this);
1520 if(this.activeItem){
1521 this.activeItem.deactivate();
1522 this.activeItem = null;
1524 this.triggerEl.removeClass('open');;
1526 this.fireEvent("hide", this);
1528 if(deep === true && this.parentMenu){
1529 this.parentMenu.hide(true);
1533 onTriggerPress : function(e)
1536 Roo.log('trigger press');
1537 //Roo.log(e.getTarget());
1538 // Roo.log(this.triggerEl.dom);
1539 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1542 if (this.isVisible()) {
1546 this.show(this.triggerEl, false, false);
1555 hideMenuItems : function()
1557 //$(backdrop).remove()
1558 Roo.select('.open',true).each(function(aa) {
1560 aa.removeClass('open');
1561 //var parent = getParent($(this))
1562 //var relatedTarget = { relatedTarget: this }
1564 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1565 //if (e.isDefaultPrevented()) return
1566 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1569 addxtypeChild : function (tree, cntr) {
1570 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1572 this.menuitems.add(comp);
1593 * @class Roo.bootstrap.MenuItem
1594 * @extends Roo.bootstrap.Component
1595 * Bootstrap MenuItem class
1596 * @cfg {String} html the menu label
1597 * @cfg {String} href the link
1598 * @cfg {Boolean} preventDefault (true | false) default true
1602 * Create a new MenuItem
1603 * @param {Object} config The config object
1607 Roo.bootstrap.MenuItem = function(config){
1608 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1613 * The raw click event for the entire grid.
1614 * @param {Roo.EventObject} e
1620 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1624 preventDefault: true,
1626 getAutoCreate : function(){
1629 cls: 'dropdown-menu-item',
1639 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1640 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1644 initEvents: function() {
1646 //this.el.select('a').on('click', this.onClick, this);
1649 onClick : function(e)
1651 Roo.log('item on click ');
1652 //if(this.preventDefault){
1653 // e.preventDefault();
1655 //this.parent().hideMenuItems();
1657 this.fireEvent('click', this, e);
1676 * @class Roo.bootstrap.MenuSeparator
1677 * @extends Roo.bootstrap.Component
1678 * Bootstrap MenuSeparator class
1681 * Create a new MenuItem
1682 * @param {Object} config The config object
1686 Roo.bootstrap.MenuSeparator = function(config){
1687 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1690 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1692 getAutoCreate : function(){
1707 <div class="modal fade">
1708 <div class="modal-dialog">
1709 <div class="modal-content">
1710 <div class="modal-header">
1711 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1712 <h4 class="modal-title">Modal title</h4>
1714 <div class="modal-body">
1715 <p>One fine body…</p>
1717 <div class="modal-footer">
1718 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1719 <button type="button" class="btn btn-primary">Save changes</button>
1721 </div><!-- /.modal-content -->
1722 </div><!-- /.modal-dialog -->
1723 </div><!-- /.modal -->
1733 * @class Roo.bootstrap.Modal
1734 * @extends Roo.bootstrap.Component
1735 * Bootstrap Modal class
1736 * @cfg {String} title Title of dialog
1737 * @cfg {Array} buttons Array of buttons or standard button set..
1740 * Create a new Modal Dialog
1741 * @param {Object} config The config object
1744 Roo.bootstrap.Modal = function(config){
1745 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1750 * The raw btnclick event for the button
1751 * @param {Roo.EventObject} e
1757 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1759 title : 'test dialog',
1763 onRender : function(ct, position)
1765 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1768 var cfg = Roo.apply({}, this.getAutoCreate());
1771 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1773 //if (!cfg.name.length) {
1777 cfg.cls += ' ' + this.cls;
1780 cfg.style = this.style;
1782 this.el = Roo.get(document.body).createChild(cfg, position);
1784 //var type = this.el.dom.type;
1786 if(this.tabIndex !== undefined){
1787 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1792 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1793 this.maskEl.enableDisplayMode("block");
1795 //this.el.addClass("x-dlg-modal");
1798 Roo.each(this.buttons, function(bb) {
1799 b = Roo.apply({}, bb);
1800 b.xns = b.xns || Roo.bootstrap;
1801 b.xtype = b.xtype || 'Button';
1802 if (typeof(b.listeners) == 'undefined') {
1803 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1806 var btn = Roo.factory(b);
1808 btn.onRender(this.el.select('.modal-footer').first());
1812 // render the children.
1815 if(typeof(this.items) != 'undefined'){
1816 var items = this.items;
1819 for(var i =0;i < items.length;i++) {
1820 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1824 this.items = nitems;
1826 //this.el.addClass([this.fieldClass, this.cls]);
1829 getAutoCreate : function(){
1834 html : this.html || ''
1842 cls: "modal-dialog",
1845 cls : "modal-content",
1848 cls : 'modal-header',
1857 cls : 'modal-title',
1865 cls : 'modal-footer'
1881 getChildContainer : function() {
1883 return this.el.select('.modal-body',true).first();
1886 getButtonContainer : function() {
1887 return this.el.select('.modal-footer',true).first();
1890 initEvents : function()
1892 this.el.select('.modal-header .close').on('click', this.hide, this);
1894 // this.addxtype(this);
1898 if (!this.rendered) {
1902 this.el.addClass('on');
1903 this.el.removeClass('fade');
1904 this.el.setStyle('display', 'block');
1905 Roo.get(document.body).addClass("x-body-masked");
1906 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1908 this.el.setStyle('zIndex', '10001');
1909 this.fireEvent('show', this);
1915 Roo.log('Modal hide?!');
1917 Roo.get(document.body).removeClass("x-body-masked");
1918 this.el.removeClass('on');
1919 this.el.addClass('fade');
1920 this.el.setStyle('display', 'none');
1921 this.fireEvent('hide', this);
1923 onButtonClick: function(btn,e)
1926 this.fireEvent('btnclick', btn.name, e);
1931 Roo.apply(Roo.bootstrap.Modal, {
1933 * Button config that displays a single OK button
1942 * Button config that displays Yes and No buttons
1958 * Button config that displays OK and Cancel buttons
1973 * Button config that displays Yes, No and Cancel buttons
2000 * @class Roo.bootstrap.Navbar
2001 * @extends Roo.bootstrap.Component
2002 * Bootstrap Navbar class
2003 * @cfg {Boolean} sidebar has side bar
2004 * @cfg {Boolean} bar is a bar?
2005 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2006 * @cfg {String} brand what is brand
2007 * @cfg {Boolean} inverse is inverted color
2008 * @cfg {String} type (nav | pills | tabs)
2009 * @cfg {Boolean} arrangement stacked | justified
2010 * @cfg {String} align (left | right) alignment
2011 * @cfg {String} brand_href href of the brand
2012 * @cfg {Boolean} main (true|false) main nav bar? default false
2016 * Create a new Navbar
2017 * @param {Object} config The config object
2021 Roo.bootstrap.Navbar = function(config){
2022 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2025 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2039 getAutoCreate : function(){
2044 if (this.sidebar === true) {
2052 if (this.bar === true) {
2060 cls: 'navbar-header',
2065 cls: 'navbar-toggle',
2066 'data-toggle': 'collapse',
2071 html: 'Toggle navigation'
2091 cls: 'collapse navbar-collapse'
2096 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2098 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2099 cfg.cls += ' navbar-' + this.position;
2100 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
2103 if (this.brand !== '') {
2106 href: this.brand_href ? this.brand_href : '#',
2107 cls: 'navbar-brand',
2115 cfg.cls += ' main-nav';
2121 } else if (this.bar === false) {
2124 Roo.log('Property \'bar\' in of Navbar must be either true or false')
2134 if (['tabs','pills'].indexOf(this.type)!==-1) {
2135 cfg.cn[0].cls += ' nav-' + this.type
2137 if (this.type!=='nav') {
2138 Roo.log('nav type must be nav/tabs/pills')
2140 cfg.cn[0].cls += ' navbar-nav'
2143 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2144 cfg.cn[0].cls += ' nav-' + this.arrangement;
2147 if (this.align === 'right') {
2148 cfg.cn[0].cls += ' navbar-right';
2151 cfg.cls += ' navbar-inverse';
2159 initEvents :function ()
2161 //Roo.log(this.el.select('.navbar-toggle',true));
2162 this.el.select('.navbar-toggle',true).on('click', function() {
2163 // Roo.log('click');
2164 this.el.select('.navbar-collapse',true).toggleClass('in');
2169 getChildContainer : function()
2171 if (this.bar === true) {
2172 return this.el.select('.collapse',true).first();
2190 * @class Roo.bootstrap.NavGroup
2191 * @extends Roo.bootstrap.Component
2192 * Bootstrap NavGroup class
2193 * @cfg {String} align left | right
2194 * @cfg {Boolean} inverse false | true
2195 * @cfg {String} type (nav|pills|tab) default nav
2198 * Create a new nav group
2199 * @param {Object} config The config object
2202 Roo.bootstrap.NavGroup = function(config){
2203 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
2206 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
2213 getAutoCreate : function(){
2214 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
2221 if (['tabs','pills'].indexOf(this.type)!==-1) {
2222 cfg.cls += ' nav-' + this.type
2224 if (this.type!=='nav') {
2225 Roo.log('nav type must be nav/tabs/pills')
2227 cfg.cls += ' navbar-nav'
2230 if (this.parent().sidebar === true) {
2233 cls: 'dashboard-menu'
2239 if (this.form === true) {
2245 if (this.align === 'right') {
2246 cfg.cls += ' navbar-right';
2248 cfg.cls += ' navbar-left';
2252 if (this.align === 'right') {
2253 cfg.cls += ' navbar-right';
2257 cfg.cls += ' navbar-inverse';
2277 * @class Roo.bootstrap.Navbar.Item
2278 * @extends Roo.bootstrap.Component
2279 * Bootstrap Navbar.Button class
2280 * @cfg {String} href link to
2281 * @cfg {String} html content of button
2282 * @cfg {String} badge text inside badge
2283 * @cfg {String} glyphicon name of glyphicon
2284 * @cfg {String} icon name of font awesome icon
2285 * @cfg {Boolena} active Is item active
2286 * @cfg {Boolean} preventDefault (true | false) default false
2289 * Create a new Navbar Button
2290 * @param {Object} config The config object
2292 Roo.bootstrap.Navbar.Item = function(config){
2293 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
2298 * The raw click event for the entire grid.
2299 * @param {Roo.EventObject} e
2305 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
2314 preventDefault : false,
2316 getAutoCreate : function(){
2318 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
2320 if (this.parent().parent().sidebar === true) {
2333 cfg.cn[0].html = this.html;
2337 this.cls += ' active';
2341 cfg.cn[0].cls += ' dropdown-toggle';
2342 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
2346 cfg.cn[0].tag = 'a',
2347 cfg.cn[0].href = this.href;
2350 if (this.glyphicon) {
2351 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2355 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2367 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
2377 if (this.glyphicon) {
2378 if(cfg.html){cfg.html = ' ' + this.html};
2382 cls: 'glyphicon glyphicon-' + this.glyphicon
2387 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2392 cfg.cn[0].html += " <span class='caret'></span>";
2393 //}else if (!this.href) {
2394 // cfg.cn[0].tag='p';
2395 // cfg.cn[0].cls='navbar-text';
2398 cfg.cn[0].href=this.href||'#';
2399 cfg.cn[0].html=this.html;
2402 if (this.badge !== '') {
2405 cfg.cn[0].html + ' ',
2416 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2421 initEvents: function() {
2422 // Roo.log('init events?');
2423 // Roo.log(this.el.dom);
2424 this.el.select('a',true).on('click', this.onClick, this);
2427 onClick : function(e)
2429 if(this.preventDefault){
2433 if(this.fireEvent('click', this, e) === false){
2437 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
2438 this.onTabsClick(e);
2442 onTabsClick : function(e)
2444 Roo.each(this.parent().el.select('.active',true).elements, function(v){
2445 v.removeClass('active');
2448 this.el.addClass('active');
2450 if(this.href && this.href.substring(0,1) == '#'){
2451 var tab = Roo.select('[tabId=' + this.href + ']', true).first();
2453 Roo.each(tab.findParent('.tab-content', 0, true).select('.active', true).elements, function(v){
2454 v.removeClass('active');
2457 tab.addClass('active');
2472 * @class Roo.bootstrap.Row
2473 * @extends Roo.bootstrap.Component
2474 * Bootstrap Row class (contains columns...)
2478 * @param {Object} config The config object
2481 Roo.bootstrap.Row = function(config){
2482 Roo.bootstrap.Row.superclass.constructor.call(this, config);
2485 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2487 getAutoCreate : function(){
2506 * @class Roo.bootstrap.Element
2507 * @extends Roo.bootstrap.Component
2508 * Bootstrap Element class
2509 * @cfg {String} html contents of the element
2510 * @cfg {String} tag tag of the element
2511 * @cfg {String} cls class of the element
2514 * Create a new Element
2515 * @param {Object} config The config object
2518 Roo.bootstrap.Element = function(config){
2519 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2522 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2529 getAutoCreate : function(){
2554 * @class Roo.bootstrap.Pagination
2555 * @extends Roo.bootstrap.Component
2556 * Bootstrap Pagination class
2557 * @cfg {String} size xs | sm | md | lg
2558 * @cfg {Boolean} inverse false | true
2561 * Create a new Pagination
2562 * @param {Object} config The config object
2565 Roo.bootstrap.Pagination = function(config){
2566 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2569 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2575 getAutoCreate : function(){
2581 cfg.cls += ' inverse';
2587 cfg.cls += " " + this.cls;
2605 * @class Roo.bootstrap.PaginationItem
2606 * @extends Roo.bootstrap.Component
2607 * Bootstrap PaginationItem class
2608 * @cfg {String} html text
2609 * @cfg {String} href the link
2610 * @cfg {Boolean} preventDefault (true | false) default true
2611 * @cfg {Boolean} active (true | false) default false
2615 * Create a new PaginationItem
2616 * @param {Object} config The config object
2620 Roo.bootstrap.PaginationItem = function(config){
2621 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2626 * The raw click event for the entire grid.
2627 * @param {Roo.EventObject} e
2633 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2637 preventDefault: true,
2641 getAutoCreate : function(){
2647 href : this.href ? this.href : '#',
2648 html : this.html ? this.html : ''
2658 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2664 initEvents: function() {
2666 this.el.on('click', this.onClick, this);
2669 onClick : function(e)
2671 Roo.log('PaginationItem on click ');
2672 if(this.preventDefault){
2676 this.fireEvent('click', this, e);
2692 * @class Roo.bootstrap.Slider
2693 * @extends Roo.bootstrap.Component
2694 * Bootstrap Slider class
2697 * Create a new Slider
2698 * @param {Object} config The config object
2701 Roo.bootstrap.Slider = function(config){
2702 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2705 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2707 getAutoCreate : function(){
2711 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2715 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2733 * @class Roo.bootstrap.Table
2734 * @extends Roo.bootstrap.Component
2735 * Bootstrap Table class
2736 * @cfg {String} cls table class
2737 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2738 * @cfg {String} bgcolor Specifies the background color for a table
2739 * @cfg {Number} border Specifies whether the table cells should have borders or not
2740 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2741 * @cfg {Number} cellspacing Specifies the space between cells
2742 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2743 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2744 * @cfg {String} sortable Specifies that the table should be sortable
2745 * @cfg {String} summary Specifies a summary of the content of a table
2746 * @cfg {Number} width Specifies the width of a table
2748 * @cfg {boolean} striped Should the rows be alternative striped
2749 * @cfg {boolean} bordered Add borders to the table
2750 * @cfg {boolean} hover Add hover highlighting
2751 * @cfg {boolean} condensed Format condensed
2752 * @cfg {boolean} responsive Format condensed
2758 * Create a new Table
2759 * @param {Object} config The config object
2762 Roo.bootstrap.Table = function(config){
2763 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2766 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2767 this.sm = this.selModel;
2768 this.sm.xmodule = this.xmodule || false;
2770 if (this.cm && typeof(this.cm.config) == 'undefined') {
2771 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2772 this.cm = this.colModel;
2773 this.cm.xmodule = this.xmodule || false;
2776 this.store= Roo.factory(this.store, Roo.data);
2777 this.ds = this.store;
2778 this.ds.xmodule = this.xmodule || false;
2783 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2805 getAutoCreate : function(){
2806 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2815 cfg.cls += ' table-striped';
2818 cfg.cls += ' table-hover';
2820 if (this.bordered) {
2821 cfg.cls += ' table-bordered';
2823 if (this.condensed) {
2824 cfg.cls += ' table-condensed';
2826 if (this.responsive) {
2827 cfg.cls += ' table-responsive';
2834 cfg.cls+= ' ' +this.cls;
2837 // this lot should be simplifed...
2840 cfg.align=this.align;
2843 cfg.bgcolor=this.bgcolor;
2846 cfg.border=this.border;
2848 if (this.cellpadding) {
2849 cfg.cellpadding=this.cellpadding;
2851 if (this.cellspacing) {
2852 cfg.cellspacing=this.cellspacing;
2855 cfg.frame=this.frame;
2858 cfg.rules=this.rules;
2860 if (this.sortable) {
2861 cfg.sortable=this.sortable;
2864 cfg.summary=this.summary;
2867 cfg.width=this.width;
2870 if(this.store || this.cm){
2871 cfg.cn.push(this.renderHeader());
2872 cfg.cn.push(this.renderBody());
2873 cfg.cn.push(this.renderFooter());
2875 cfg.cls+= ' TableGrid';
2881 // initTableGrid : function()
2890 // var cm = this.cm;
2892 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2895 // html: cm.getColumnHeader(i)
2899 // cfg.push(header);
2906 initEvents : function()
2908 if(!this.store || !this.cm){
2912 Roo.log('initEvents with ds!!!!');
2914 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
2915 // this.maskEl.enableDisplayMode("block");
2916 // this.maskEl.show();
2918 this.store.on('load', this.onLoad, this);
2919 this.store.on('beforeload', this.onBeforeLoad, this);
2927 renderHeader : function()
2936 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2939 html: cm.getColumnHeader(i)
2946 renderBody : function()
2956 renderFooter : function()
2968 Roo.log('ds onload');
2972 var tbody = this.el.select('tbody', true).first();
2976 if(this.store.getCount() > 0){
2977 this.store.data.each(function(d){
2983 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2984 var renderer = cm.getRenderer(i);
2988 if(typeof(renderer) !== 'undefined'){
2989 value = renderer(d.data[cm.getDataIndex(i)], false, d);
2992 if(typeof(value) === 'object'){
3002 html: (typeof(value) === 'object') ? '' : value
3007 tbody.createChild(row);
3013 Roo.each(renders, function(r){
3014 r.cfg.render(Roo.get(r.id));
3018 // if(this.loadMask){
3019 // this.maskEl.hide();
3023 onBeforeLoad : function()
3025 Roo.log('ds onBeforeLoad');
3029 // if(this.loadMask){
3030 // this.maskEl.show();
3036 this.el.select('tbody', true).first().dom.innerHTML = '';
3039 getSelectionModel : function(){
3041 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3043 return this.selModel;
3058 * @class Roo.bootstrap.TableCell
3059 * @extends Roo.bootstrap.Component
3060 * Bootstrap TableCell class
3061 * @cfg {String} html cell contain text
3062 * @cfg {String} cls cell class
3063 * @cfg {String} tag cell tag (td|th) default td
3064 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3065 * @cfg {String} align Aligns the content in a cell
3066 * @cfg {String} axis Categorizes cells
3067 * @cfg {String} bgcolor Specifies the background color of a cell
3068 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3069 * @cfg {Number} colspan Specifies the number of columns a cell should span
3070 * @cfg {String} headers Specifies one or more header cells a cell is related to
3071 * @cfg {Number} height Sets the height of a cell
3072 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3073 * @cfg {Number} rowspan Sets the number of rows a cell should span
3074 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3075 * @cfg {String} valign Vertical aligns the content in a cell
3076 * @cfg {Number} width Specifies the width of a cell
3079 * Create a new TableCell
3080 * @param {Object} config The config object
3083 Roo.bootstrap.TableCell = function(config){
3084 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3087 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3107 getAutoCreate : function(){
3108 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3128 cfg.align=this.align
3134 cfg.bgcolor=this.bgcolor
3137 cfg.charoff=this.charoff
3140 cfg.colspan=this.colspan
3143 cfg.headers=this.headers
3146 cfg.height=this.height
3149 cfg.nowrap=this.nowrap
3152 cfg.rowspan=this.rowspan
3155 cfg.scope=this.scope
3158 cfg.valign=this.valign
3161 cfg.width=this.width
3180 * @class Roo.bootstrap.TableRow
3181 * @extends Roo.bootstrap.Component
3182 * Bootstrap TableRow class
3183 * @cfg {String} cls row class
3184 * @cfg {String} align Aligns the content in a table row
3185 * @cfg {String} bgcolor Specifies a background color for a table row
3186 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3187 * @cfg {String} valign Vertical aligns the content in a table row
3190 * Create a new TableRow
3191 * @param {Object} config The config object
3194 Roo.bootstrap.TableRow = function(config){
3195 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
3198 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
3206 getAutoCreate : function(){
3207 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
3217 cfg.align = this.align;
3220 cfg.bgcolor = this.bgcolor;
3223 cfg.charoff = this.charoff;
3226 cfg.valign = this.valign;
3244 * @class Roo.bootstrap.TableBody
3245 * @extends Roo.bootstrap.Component
3246 * Bootstrap TableBody class
3247 * @cfg {String} cls element class
3248 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
3249 * @cfg {String} align Aligns the content inside the element
3250 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
3251 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
3254 * Create a new TableBody
3255 * @param {Object} config The config object
3258 Roo.bootstrap.TableBody = function(config){
3259 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
3262 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
3270 getAutoCreate : function(){
3271 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
3285 cfg.align = this.align;
3288 cfg.charoff = this.charoff;
3291 cfg.valign = this.valign;
3298 // initEvents : function()
3305 // this.store = Roo.factory(this.store, Roo.data);
3306 // this.store.on('load', this.onLoad, this);
3308 // this.store.load();
3312 // onLoad: function ()
3314 // this.fireEvent('load', this);
3324 * Ext JS Library 1.1.1
3325 * Copyright(c) 2006-2007, Ext JS, LLC.
3327 * Originally Released Under LGPL - original licence link has changed is not relivant.
3330 * <script type="text/javascript">
3333 // as we use this in bootstrap.
3334 Roo.namespace('Roo.form');
3336 * @class Roo.form.Action
3337 * Internal Class used to handle form actions
3339 * @param {Roo.form.BasicForm} el The form element or its id
3340 * @param {Object} config Configuration options
3345 // define the action interface
3346 Roo.form.Action = function(form, options){
3348 this.options = options || {};
3351 * Client Validation Failed
3354 Roo.form.Action.CLIENT_INVALID = 'client';
3356 * Server Validation Failed
3359 Roo.form.Action.SERVER_INVALID = 'server';
3361 * Connect to Server Failed
3364 Roo.form.Action.CONNECT_FAILURE = 'connect';
3366 * Reading Data from Server Failed
3369 Roo.form.Action.LOAD_FAILURE = 'load';
3371 Roo.form.Action.prototype = {
3373 failureType : undefined,
3374 response : undefined,
3378 run : function(options){
3383 success : function(response){
3388 handleResponse : function(response){
3392 // default connection failure
3393 failure : function(response){
3395 this.response = response;
3396 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3397 this.form.afterAction(this, false);
3400 processResponse : function(response){
3401 this.response = response;
3402 if(!response.responseText){
3405 this.result = this.handleResponse(response);
3409 // utility functions used internally
3410 getUrl : function(appendParams){
3411 var url = this.options.url || this.form.url || this.form.el.dom.action;
3413 var p = this.getParams();
3415 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
3421 getMethod : function(){
3422 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
3425 getParams : function(){
3426 var bp = this.form.baseParams;
3427 var p = this.options.params;
3429 if(typeof p == "object"){
3430 p = Roo.urlEncode(Roo.applyIf(p, bp));
3431 }else if(typeof p == 'string' && bp){
3432 p += '&' + Roo.urlEncode(bp);
3435 p = Roo.urlEncode(bp);
3440 createCallback : function(){
3442 success: this.success,
3443 failure: this.failure,
3445 timeout: (this.form.timeout*1000),
3446 upload: this.form.fileUpload ? this.success : undefined
3451 Roo.form.Action.Submit = function(form, options){
3452 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
3455 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
3458 haveProgress : false,
3459 uploadComplete : false,
3461 // uploadProgress indicator.
3462 uploadProgress : function()
3464 if (!this.form.progressUrl) {
3468 if (!this.haveProgress) {
3469 Roo.MessageBox.progress("Uploading", "Uploading");
3471 if (this.uploadComplete) {
3472 Roo.MessageBox.hide();
3476 this.haveProgress = true;
3478 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
3480 var c = new Roo.data.Connection();
3482 url : this.form.progressUrl,
3487 success : function(req){
3488 //console.log(data);
3492 rdata = Roo.decode(req.responseText)
3494 Roo.log("Invalid data from server..");
3498 if (!rdata || !rdata.success) {
3500 Roo.MessageBox.alert(Roo.encode(rdata));
3503 var data = rdata.data;
3505 if (this.uploadComplete) {
3506 Roo.MessageBox.hide();
3511 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3512 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3515 this.uploadProgress.defer(2000,this);
3518 failure: function(data) {
3519 Roo.log('progress url failed ');
3530 // run get Values on the form, so it syncs any secondary forms.
3531 this.form.getValues();
3533 var o = this.options;
3534 var method = this.getMethod();
3535 var isPost = method == 'POST';
3536 if(o.clientValidation === false || this.form.isValid()){
3538 if (this.form.progressUrl) {
3539 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3540 (new Date() * 1) + '' + Math.random());
3545 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3546 form:this.form.el.dom,
3547 url:this.getUrl(!isPost),
3549 params:isPost ? this.getParams() : null,
3550 isUpload: this.form.fileUpload
3553 this.uploadProgress();
3555 }else if (o.clientValidation !== false){ // client validation failed
3556 this.failureType = Roo.form.Action.CLIENT_INVALID;
3557 this.form.afterAction(this, false);
3561 success : function(response)
3563 this.uploadComplete= true;
3564 if (this.haveProgress) {
3565 Roo.MessageBox.hide();
3569 var result = this.processResponse(response);
3570 if(result === true || result.success){
3571 this.form.afterAction(this, true);
3575 this.form.markInvalid(result.errors);
3576 this.failureType = Roo.form.Action.SERVER_INVALID;
3578 this.form.afterAction(this, false);
3580 failure : function(response)
3582 this.uploadComplete= true;
3583 if (this.haveProgress) {
3584 Roo.MessageBox.hide();
3587 this.response = response;
3588 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3589 this.form.afterAction(this, false);
3592 handleResponse : function(response){
3593 if(this.form.errorReader){
3594 var rs = this.form.errorReader.read(response);
3597 for(var i = 0, len = rs.records.length; i < len; i++) {
3598 var r = rs.records[i];
3602 if(errors.length < 1){
3606 success : rs.success,
3612 ret = Roo.decode(response.responseText);
3616 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3626 Roo.form.Action.Load = function(form, options){
3627 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3628 this.reader = this.form.reader;
3631 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3636 Roo.Ajax.request(Roo.apply(
3637 this.createCallback(), {
3638 method:this.getMethod(),
3639 url:this.getUrl(false),
3640 params:this.getParams()
3644 success : function(response){
3646 var result = this.processResponse(response);
3647 if(result === true || !result.success || !result.data){
3648 this.failureType = Roo.form.Action.LOAD_FAILURE;
3649 this.form.afterAction(this, false);
3652 this.form.clearInvalid();
3653 this.form.setValues(result.data);
3654 this.form.afterAction(this, true);
3657 handleResponse : function(response){
3658 if(this.form.reader){
3659 var rs = this.form.reader.read(response);
3660 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3662 success : rs.success,
3666 return Roo.decode(response.responseText);
3670 Roo.form.Action.ACTION_TYPES = {
3671 'load' : Roo.form.Action.Load,
3672 'submit' : Roo.form.Action.Submit
3681 * @class Roo.bootstrap.Form
3682 * @extends Roo.bootstrap.Component
3683 * Bootstrap Form class
3684 * @cfg {String} method GET | POST (default POST)
3685 * @cfg {String} labelAlign top | left (default top)
3686 * @cfg {String} align left | right - for navbars
3691 * @param {Object} config The config object
3695 Roo.bootstrap.Form = function(config){
3696 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3699 * @event clientvalidation
3700 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3701 * @param {Form} this
3702 * @param {Boolean} valid true if the form has passed client-side validation
3704 clientvalidation: true,
3706 * @event beforeaction
3707 * Fires before any action is performed. Return false to cancel the action.
3708 * @param {Form} this
3709 * @param {Action} action The action to be performed
3713 * @event actionfailed
3714 * Fires when an action fails.
3715 * @param {Form} this
3716 * @param {Action} action The action that failed
3718 actionfailed : true,
3720 * @event actioncomplete
3721 * Fires when an action is completed.
3722 * @param {Form} this
3723 * @param {Action} action The action that completed
3725 actioncomplete : true
3730 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3733 * @cfg {String} method
3734 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3739 * The URL to use for form actions if one isn't supplied in the action options.
3742 * @cfg {Boolean} fileUpload
3743 * Set to true if this form is a file upload.
3747 * @cfg {Object} baseParams
3748 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3752 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3756 * @cfg {Sting} align (left|right) for navbar forms
3761 activeAction : null,
3764 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3765 * element by passing it or its id or mask the form itself by passing in true.
3768 waitMsgTarget : false,
3773 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3774 * element by passing it or its id or mask the form itself by passing in true.
3778 getAutoCreate : function(){
3782 method : this.method || 'POST',
3783 id : this.id || Roo.id(),
3786 if (this.parent().xtype.match(/^Nav/)) {
3787 cfg.cls = 'navbar-form navbar-' + this.align;
3791 if (this.labelAlign == 'left' ) {
3792 cfg.cls += ' form-horizontal';
3798 initEvents : function()
3800 this.el.on('submit', this.onSubmit, this);
3805 onSubmit : function(e){
3810 * Returns true if client-side validation on the form is successful.
3813 isValid : function(){
3814 var items = this.getItems();
3816 items.each(function(f){
3825 * Returns true if any fields in this form have changed since their original load.
3828 isDirty : function(){
3830 var items = this.getItems();
3831 items.each(function(f){
3841 * Performs a predefined action (submit or load) or custom actions you define on this form.
3842 * @param {String} actionName The name of the action type
3843 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3844 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3845 * accept other config options):
3847 Property Type Description
3848 ---------------- --------------- ----------------------------------------------------------------------------------
3849 url String The url for the action (defaults to the form's url)
3850 method String The form method to use (defaults to the form's method, or POST if not defined)
3851 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3852 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3853 validate the form on the client (defaults to false)
3855 * @return {BasicForm} this
3857 doAction : function(action, options){
3858 if(typeof action == 'string'){
3859 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3861 if(this.fireEvent('beforeaction', this, action) !== false){
3862 this.beforeAction(action);
3863 action.run.defer(100, action);
3869 beforeAction : function(action){
3870 var o = action.options;
3872 // not really supported yet.. ??
3874 //if(this.waitMsgTarget === true){
3875 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3876 //}else if(this.waitMsgTarget){
3877 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3878 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3880 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3886 afterAction : function(action, success){
3887 this.activeAction = null;
3888 var o = action.options;
3890 //if(this.waitMsgTarget === true){
3892 //}else if(this.waitMsgTarget){
3893 // this.waitMsgTarget.unmask();
3895 // Roo.MessageBox.updateProgress(1);
3896 // Roo.MessageBox.hide();
3903 Roo.callback(o.success, o.scope, [this, action]);
3904 this.fireEvent('actioncomplete', this, action);
3908 // failure condition..
3909 // we have a scenario where updates need confirming.
3910 // eg. if a locking scenario exists..
3911 // we look for { errors : { needs_confirm : true }} in the response.
3913 (typeof(action.result) != 'undefined') &&
3914 (typeof(action.result.errors) != 'undefined') &&
3915 (typeof(action.result.errors.needs_confirm) != 'undefined')
3918 Roo.log("not supported yet");
3921 Roo.MessageBox.confirm(
3922 "Change requires confirmation",
3923 action.result.errorMsg,
3928 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3938 Roo.callback(o.failure, o.scope, [this, action]);
3939 // show an error message if no failed handler is set..
3940 if (!this.hasListener('actionfailed')) {
3941 Roo.log("need to add dialog support");
3943 Roo.MessageBox.alert("Error",
3944 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
3945 action.result.errorMsg :
3946 "Saving Failed, please check your entries or try again"
3951 this.fireEvent('actionfailed', this, action);
3956 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
3957 * @param {String} id The value to search for
3960 findField : function(id){
3961 var items = this.getItems();
3962 var field = items.get(id);
3964 items.each(function(f){
3965 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
3972 return field || null;
3975 * Mark fields in this form invalid in bulk.
3976 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
3977 * @return {BasicForm} this
3979 markInvalid : function(errors){
3980 if(errors instanceof Array){
3981 for(var i = 0, len = errors.length; i < len; i++){
3982 var fieldError = errors[i];
3983 var f = this.findField(fieldError.id);
3985 f.markInvalid(fieldError.msg);
3991 if(typeof errors[id] != 'function' && (field = this.findField(id))){
3992 field.markInvalid(errors[id]);
3996 //Roo.each(this.childForms || [], function (f) {
3997 // f.markInvalid(errors);
4004 * Set values for fields in this form in bulk.
4005 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4006 * @return {BasicForm} this
4008 setValues : function(values){
4009 if(values instanceof Array){ // array of objects
4010 for(var i = 0, len = values.length; i < len; i++){
4012 var f = this.findField(v.id);
4014 f.setValue(v.value);
4015 if(this.trackResetOnLoad){
4016 f.originalValue = f.getValue();
4020 }else{ // object hash
4023 if(typeof values[id] != 'function' && (field = this.findField(id))){
4025 if (field.setFromData &&
4027 field.displayField &&
4028 // combos' with local stores can
4029 // be queried via setValue()
4030 // to set their value..
4031 (field.store && !field.store.isLocal)
4035 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4036 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4037 field.setFromData(sd);
4040 field.setValue(values[id]);
4044 if(this.trackResetOnLoad){
4045 field.originalValue = field.getValue();
4051 //Roo.each(this.childForms || [], function (f) {
4052 // f.setValues(values);
4059 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4060 * they are returned as an array.
4061 * @param {Boolean} asString
4064 getValues : function(asString){
4065 //if (this.childForms) {
4066 // copy values from the child forms
4067 // Roo.each(this.childForms, function (f) {
4068 // this.setValues(f.getValues());
4074 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4075 if(asString === true){
4078 return Roo.urlDecode(fs);
4082 * Returns the fields in this form as an object with key/value pairs.
4083 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4086 getFieldValues : function(with_hidden)
4088 var items = this.getItems();
4090 items.each(function(f){
4094 var v = f.getValue();
4095 if (f.inputType =='radio') {
4096 if (typeof(ret[f.getName()]) == 'undefined') {
4097 ret[f.getName()] = ''; // empty..
4100 if (!f.el.dom.checked) {
4108 // not sure if this supported any more..
4109 if ((typeof(v) == 'object') && f.getRawValue) {
4110 v = f.getRawValue() ; // dates..
4112 // combo boxes where name != hiddenName...
4113 if (f.name != f.getName()) {
4114 ret[f.name] = f.getRawValue();
4116 ret[f.getName()] = v;
4123 * Clears all invalid messages in this form.
4124 * @return {BasicForm} this
4126 clearInvalid : function(){
4127 var items = this.getItems();
4129 items.each(function(f){
4140 * @return {BasicForm} this
4143 var items = this.getItems();
4144 items.each(function(f){
4148 Roo.each(this.childForms || [], function (f) {
4155 getItems : function()
4157 var r=new Roo.util.MixedCollection(false, function(o){
4158 return o.id || (o.id = Roo.id());
4160 var iter = function(el) {
4167 Roo.each(el.items,function(e) {
4186 * Ext JS Library 1.1.1
4187 * Copyright(c) 2006-2007, Ext JS, LLC.
4189 * Originally Released Under LGPL - original licence link has changed is not relivant.
4192 * <script type="text/javascript">
4195 * @class Roo.form.VTypes
4196 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
4199 Roo.form.VTypes = function(){
4200 // closure these in so they are only created once.
4201 var alpha = /^[a-zA-Z_]+$/;
4202 var alphanum = /^[a-zA-Z0-9_]+$/;
4203 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
4204 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
4206 // All these messages and functions are configurable
4209 * The function used to validate email addresses
4210 * @param {String} value The email address
4212 'email' : function(v){
4213 return email.test(v);
4216 * The error text to display when the email validation function returns false
4219 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
4221 * The keystroke filter mask to be applied on email input
4224 'emailMask' : /[a-z0-9_\.\-@]/i,
4227 * The function used to validate URLs
4228 * @param {String} value The URL
4230 'url' : function(v){
4234 * The error text to display when the url validation function returns false
4237 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
4240 * The function used to validate alpha values
4241 * @param {String} value The value
4243 'alpha' : function(v){
4244 return alpha.test(v);
4247 * The error text to display when the alpha validation function returns false
4250 'alphaText' : 'This field should only contain letters and _',
4252 * The keystroke filter mask to be applied on alpha input
4255 'alphaMask' : /[a-z_]/i,
4258 * The function used to validate alphanumeric values
4259 * @param {String} value The value
4261 'alphanum' : function(v){
4262 return alphanum.test(v);
4265 * The error text to display when the alphanumeric validation function returns false
4268 'alphanumText' : 'This field should only contain letters, numbers and _',
4270 * The keystroke filter mask to be applied on alphanumeric input
4273 'alphanumMask' : /[a-z0-9_]/i
4283 * @class Roo.bootstrap.Input
4284 * @extends Roo.bootstrap.Component
4285 * Bootstrap Input class
4286 * @cfg {Boolean} disabled is it disabled
4287 * @cfg {String} fieldLabel - the label associated
4288 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
4289 * @cfg {String} name name of the input
4290 * @cfg {string} fieldLabel - the label associated
4291 * @cfg {string} inputType - input / file submit ...
4292 * @cfg {string} placeholder - placeholder to put in text.
4293 * @cfg {string} before - input group add on before
4294 * @cfg {string} after - input group add on after
4295 * @cfg {string} size - (lg|sm) or leave empty..
4296 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
4297 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
4298 * @cfg {Number} md colspan out of 12 for computer-sized screens
4299 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
4300 * @cfg {string} value default value of the input
4301 * @cfg {Number} labelWidth set the width of label (0-12)
4302 * @cfg {String} labelAlign (top|left)
4306 * Create a new Input
4307 * @param {Object} config The config object
4310 Roo.bootstrap.Input = function(config){
4311 Roo.bootstrap.Input.superclass.constructor.call(this, config);
4316 * Fires when this field receives input focus.
4317 * @param {Roo.form.Field} this
4322 * Fires when this field loses input focus.
4323 * @param {Roo.form.Field} this
4328 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
4329 * {@link Roo.EventObject#getKey} to determine which key was pressed.
4330 * @param {Roo.form.Field} this
4331 * @param {Roo.EventObject} e The event object
4336 * Fires just before the field blurs if the field value has changed.
4337 * @param {Roo.form.Field} this
4338 * @param {Mixed} newValue The new value
4339 * @param {Mixed} oldValue The original value
4344 * Fires after the field has been marked as invalid.
4345 * @param {Roo.form.Field} this
4346 * @param {String} msg The validation message
4351 * Fires after the field has been validated with no errors.
4352 * @param {Roo.form.Field} this
4357 * Fires after the key up
4358 * @param {Roo.form.Field} this
4359 * @param {Roo.EventObject} e The event Object
4365 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
4367 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
4368 automatic validation (defaults to "keyup").
4370 validationEvent : "keyup",
4372 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
4374 validateOnBlur : true,
4376 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
4378 validationDelay : 250,
4380 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
4382 focusClass : "x-form-focus", // not needed???
4386 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
4388 invalidClass : "has-error",
4391 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
4393 selectOnFocus : false,
4396 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
4400 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
4405 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
4407 disableKeyFilter : false,
4410 * @cfg {Boolean} disabled True to disable the field (defaults to false).
4414 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
4418 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
4420 blankText : "This field is required",
4423 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
4427 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
4429 maxLength : Number.MAX_VALUE,
4431 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
4433 minLengthText : "The minimum length for this field is {0}",
4435 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
4437 maxLengthText : "The maximum length for this field is {0}",
4441 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
4442 * If available, this function will be called only after the basic validators all return true, and will be passed the
4443 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
4447 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
4448 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
4449 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
4453 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
4475 parentLabelAlign : function()
4478 while (parent.parent()) {
4479 parent = parent.parent();
4480 if (typeof(parent.labelAlign) !='undefined') {
4481 return parent.labelAlign;
4488 getAutoCreate : function(){
4490 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4496 if(this.inputType != 'hidden'){
4497 cfg.cls = 'form-group' //input-group
4503 type : this.inputType,
4505 cls : 'form-control',
4506 placeholder : this.placeholder || ''
4510 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4511 input.maxLength = this.maxLength;
4514 if (this.disabled) {
4515 input.disabled=true;
4519 input.name = this.name;
4522 input.cls += ' input-' + this.size;
4525 ['xs','sm','md','lg'].map(function(size){
4526 if (settings[size]) {
4527 cfg.cls += ' col-' + size + '-' + settings[size];
4531 var inputblock = input;
4533 if (this.before || this.after) {
4536 cls : 'input-group',
4540 inputblock.cn.push({
4542 cls : 'input-group-addon',
4546 inputblock.cn.push(input);
4548 inputblock.cn.push({
4550 cls : 'input-group-addon',
4557 if (align ==='left' && this.fieldLabel.length) {
4558 Roo.log("left and has label");
4564 cls : 'control-label col-sm-' + this.labelWidth,
4565 html : this.fieldLabel
4569 cls : "col-sm-" + (12 - this.labelWidth),
4576 } else if ( this.fieldLabel.length) {
4582 //cls : 'input-group-addon',
4583 html : this.fieldLabel
4593 Roo.log(" no label && no align");
4602 Roo.log('input-parentType: ' + this.parentType);
4604 if (this.parentType === 'Navbar' && this.parent().bar) {
4605 cfg.cls += ' navbar-form';
4613 * return the real input element.
4615 inputEl: function ()
4617 return this.el.select('input.form-control',true).first();
4619 setDisabled : function(v)
4621 var i = this.inputEl().dom;
4623 i.removeAttribute('disabled');
4627 i.setAttribute('disabled','true');
4629 initEvents : function()
4632 this.inputEl().on("keydown" , this.fireKey, this);
4633 this.inputEl().on("focus", this.onFocus, this);
4634 this.inputEl().on("blur", this.onBlur, this);
4636 this.inputEl().relayEvent('keyup', this);
4638 // reference to original value for reset
4639 this.originalValue = this.getValue();
4640 //Roo.form.TextField.superclass.initEvents.call(this);
4641 if(this.validationEvent == 'keyup'){
4642 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4643 this.inputEl().on('keyup', this.filterValidation, this);
4645 else if(this.validationEvent !== false){
4646 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4649 if(this.selectOnFocus){
4650 this.on("focus", this.preFocus, this);
4653 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4654 this.inputEl().on("keypress", this.filterKeys, this);
4657 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4658 this.el.on("click", this.autoSize, this);
4661 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4662 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4666 filterValidation : function(e){
4667 if(!e.isNavKeyPress()){
4668 this.validationTask.delay(this.validationDelay);
4672 * Validates the field value
4673 * @return {Boolean} True if the value is valid, else false
4675 validate : function(){
4676 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4677 if(this.disabled || this.validateValue(this.getRawValue())){
4678 this.clearInvalid();
4686 * Validates a value according to the field's validation rules and marks the field as invalid
4687 * if the validation fails
4688 * @param {Mixed} value The value to validate
4689 * @return {Boolean} True if the value is valid, else false
4691 validateValue : function(value){
4692 if(value.length < 1) { // if it's blank
4693 if(this.allowBlank){
4694 this.clearInvalid();
4697 this.markInvalid(this.blankText);
4701 if(value.length < this.minLength){
4702 this.markInvalid(String.format(this.minLengthText, this.minLength));
4705 if(value.length > this.maxLength){
4706 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4710 var vt = Roo.form.VTypes;
4711 if(!vt[this.vtype](value, this)){
4712 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4716 if(typeof this.validator == "function"){
4717 var msg = this.validator(value);
4719 this.markInvalid(msg);
4723 if(this.regex && !this.regex.test(value)){
4724 this.markInvalid(this.regexText);
4733 fireKey : function(e){
4734 //Roo.log('field ' + e.getKey());
4735 if(e.isNavKeyPress()){
4736 this.fireEvent("specialkey", this, e);
4739 focus : function (selectText){
4741 this.inputEl().focus();
4742 if(selectText === true){
4743 this.inputEl().dom.select();
4749 onFocus : function(){
4750 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4751 // this.el.addClass(this.focusClass);
4754 this.hasFocus = true;
4755 this.startValue = this.getValue();
4756 this.fireEvent("focus", this);
4760 beforeBlur : Roo.emptyFn,
4764 onBlur : function(){
4766 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4767 //this.el.removeClass(this.focusClass);
4769 this.hasFocus = false;
4770 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4773 var v = this.getValue();
4774 if(String(v) !== String(this.startValue)){
4775 this.fireEvent('change', this, v, this.startValue);
4777 this.fireEvent("blur", this);
4781 * Resets the current field value to the originally loaded value and clears any validation messages
4784 this.setValue(this.originalValue);
4785 this.clearInvalid();
4788 * Returns the name of the field
4789 * @return {Mixed} name The name field
4791 getName: function(){
4795 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4796 * @return {Mixed} value The field value
4798 getValue : function(){
4799 return this.inputEl().getValue();
4802 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4803 * @return {Mixed} value The field value
4805 getRawValue : function(){
4806 var v = this.inputEl().getValue();
4812 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4813 * @param {Mixed} value The value to set
4815 setRawValue : function(v){
4816 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4819 selectText : function(start, end){
4820 var v = this.getRawValue();
4822 start = start === undefined ? 0 : start;
4823 end = end === undefined ? v.length : end;
4824 var d = this.inputEl().dom;
4825 if(d.setSelectionRange){
4826 d.setSelectionRange(start, end);
4827 }else if(d.createTextRange){
4828 var range = d.createTextRange();
4829 range.moveStart("character", start);
4830 range.moveEnd("character", v.length-end);
4837 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4838 * @param {Mixed} value The value to set
4840 setValue : function(v){
4843 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4849 processValue : function(value){
4850 if(this.stripCharsRe){
4851 var newValue = value.replace(this.stripCharsRe, '');
4852 if(newValue !== value){
4853 this.setRawValue(newValue);
4860 preFocus : function(){
4862 if(this.selectOnFocus){
4863 this.inputEl().dom.select();
4866 filterKeys : function(e){
4868 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4871 var c = e.getCharCode(), cc = String.fromCharCode(c);
4872 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4875 if(!this.maskRe.test(cc)){
4880 * Clear any invalid styles/messages for this field
4882 clearInvalid : function(){
4884 if(!this.el || this.preventMark){ // not rendered
4887 this.el.removeClass(this.invalidClass);
4889 switch(this.msgTarget){
4891 this.el.dom.qtip = '';
4894 this.el.dom.title = '';
4898 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4903 this.errorIcon.dom.qtip = '';
4904 this.errorIcon.hide();
4905 this.un('resize', this.alignErrorIcon, this);
4909 var t = Roo.getDom(this.msgTarget);
4911 t.style.display = 'none';
4915 this.fireEvent('valid', this);
4918 * Mark this field as invalid
4919 * @param {String} msg The validation message
4921 markInvalid : function(msg){
4922 if(!this.el || this.preventMark){ // not rendered
4925 this.el.addClass(this.invalidClass);
4927 msg = msg || this.invalidText;
4928 switch(this.msgTarget){
4930 this.el.dom.qtip = msg;
4931 this.el.dom.qclass = 'x-form-invalid-tip';
4932 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4933 Roo.QuickTips.enable();
4937 this.el.dom.title = msg;
4941 var elp = this.el.findParent('.x-form-element', 5, true);
4942 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
4943 this.errorEl.setWidth(elp.getWidth(true)-20);
4945 this.errorEl.update(msg);
4946 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
4949 if(!this.errorIcon){
4950 var elp = this.el.findParent('.x-form-element', 5, true);
4951 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
4953 this.alignErrorIcon();
4954 this.errorIcon.dom.qtip = msg;
4955 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
4956 this.errorIcon.show();
4957 this.on('resize', this.alignErrorIcon, this);
4960 var t = Roo.getDom(this.msgTarget);
4962 t.style.display = this.msgDisplay;
4966 this.fireEvent('invalid', this, msg);
4969 SafariOnKeyDown : function(event)
4971 // this is a workaround for a password hang bug on chrome/ webkit.
4973 var isSelectAll = false;
4975 if(this.inputEl().dom.selectionEnd > 0){
4976 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
4978 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
4979 event.preventDefault();
4984 if(isSelectAll){ // backspace and delete key
4986 event.preventDefault();
4987 // this is very hacky as keydown always get's upper case.
4989 var cc = String.fromCharCode(event.getCharCode());
4990 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
4994 adjustWidth : function(tag, w){
4995 tag = tag.toLowerCase();
4996 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
4997 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5001 if(tag == 'textarea'){
5004 }else if(Roo.isOpera){
5008 if(tag == 'textarea'){
5027 * @class Roo.bootstrap.TextArea
5028 * @extends Roo.bootstrap.Input
5029 * Bootstrap TextArea class
5030 * @cfg {Number} cols Specifies the visible width of a text area
5031 * @cfg {Number} rows Specifies the visible number of lines in a text area
5032 * @cfg {Number} readOnly Specifies that a text area should be read-only
5033 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5034 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5035 * @cfg {string} html text
5038 * Create a new TextArea
5039 * @param {Object} config The config object
5042 Roo.bootstrap.TextArea = function(config){
5043 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5047 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5057 getAutoCreate : function(){
5059 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5070 value : this.value || '',
5071 html: this.html || '',
5072 cls : 'form-control',
5073 placeholder : this.placeholder || ''
5077 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5078 input.maxLength = this.maxLength;
5082 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5086 input.cols = this.cols;
5089 if (this.readOnly) {
5090 input.readonly = true;
5094 input.name = this.name;
5098 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5102 ['xs','sm','md','lg'].map(function(size){
5103 if (settings[size]) {
5104 cfg.cls += ' col-' + size + '-' + settings[size];
5108 var inputblock = input;
5110 if (this.before || this.after) {
5113 cls : 'input-group',
5117 inputblock.cn.push({
5119 cls : 'input-group-addon',
5123 inputblock.cn.push(input);
5125 inputblock.cn.push({
5127 cls : 'input-group-addon',
5134 if (align ==='left' && this.fieldLabel.length) {
5135 Roo.log("left and has label");
5141 cls : 'control-label col-sm-' + this.labelWidth,
5142 html : this.fieldLabel
5146 cls : "col-sm-" + (12 - this.labelWidth),
5153 } else if ( this.fieldLabel.length) {
5159 //cls : 'input-group-addon',
5160 html : this.fieldLabel
5170 Roo.log(" no label && no align");
5180 if (this.disabled) {
5181 input.disabled=true;
5188 * return the real textarea element.
5190 inputEl: function ()
5192 return this.el.select('textarea.form-control',true).first();
5200 * trigger field - base class for combo..
5205 * @class Roo.bootstrap.TriggerField
5206 * @extends Roo.bootstrap.Input
5207 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
5208 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
5209 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
5210 * for which you can provide a custom implementation. For example:
5212 var trigger = new Roo.bootstrap.TriggerField();
5213 trigger.onTriggerClick = myTriggerFn;
5214 trigger.applyTo('my-field');
5217 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
5218 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
5219 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
5220 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
5222 * Create a new TriggerField.
5223 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
5224 * to the base TextField)
5226 Roo.bootstrap.TriggerField = function(config){
5227 this.mimicing = false;
5228 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
5231 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
5233 * @cfg {String} triggerClass A CSS class to apply to the trigger
5236 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
5240 /** @cfg {Boolean} grow @hide */
5241 /** @cfg {Number} growMin @hide */
5242 /** @cfg {Number} growMax @hide */
5248 autoSize: Roo.emptyFn,
5255 actionMode : 'wrap',
5259 getAutoCreate : function(){
5261 var parent = this.parent();
5263 var align = this.parentLabelAlign();
5268 cls: 'form-group' //input-group
5275 type : this.inputType,
5276 cls : 'form-control',
5277 autocomplete: 'off',
5278 placeholder : this.placeholder || ''
5282 input.name = this.name;
5285 input.cls += ' input-' + this.size;
5288 if (this.disabled) {
5289 input.disabled=true;
5292 var inputblock = input;
5294 if (this.before || this.after) {
5297 cls : 'input-group',
5301 inputblock.cn.push({
5303 cls : 'input-group-addon',
5307 inputblock.cn.push(input);
5309 inputblock.cn.push({
5311 cls : 'input-group-addon',
5324 cls: 'form-hidden-field'
5332 Roo.log('multiple');
5340 cls: 'form-hidden-field'
5344 cls: 'select2-choices',
5348 cls: 'select2-search-field',
5361 cls: 'select2-container input-group',
5366 cls: 'typeahead typeahead-long dropdown-menu',
5367 style: 'display:none'
5375 cls : 'input-group-addon btn dropdown-toggle',
5383 cls: 'combobox-clear',
5397 combobox.cls += ' select2-container-multi';
5400 if (align ==='left' && this.fieldLabel.length) {
5404 Roo.log("left and has label");
5410 cls : 'col-sm-2 control-label',
5411 html : this.fieldLabel
5422 } else if ( this.fieldLabel.length) {
5428 //cls : 'input-group-addon',
5429 html : this.fieldLabel
5439 Roo.log(" no label && no align");
5446 ['xs','sm','md','lg'].map(function(size){
5447 if (settings[size]) {
5448 cfg.cls += ' col-' + size + '-' + settings[size];
5459 onResize : function(w, h){
5460 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
5461 // if(typeof w == 'number'){
5462 // var x = w - this.trigger.getWidth();
5463 // this.inputEl().setWidth(this.adjustWidth('input', x));
5464 // this.trigger.setStyle('left', x+'px');
5469 adjustSize : Roo.BoxComponent.prototype.adjustSize,
5472 getResizeEl : function(){
5473 return this.inputEl();
5477 getPositionEl : function(){
5478 return this.inputEl();
5482 alignErrorIcon : function(){
5483 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
5487 initEvents : function(){
5489 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
5490 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
5492 this.trigger = this.el.select('span.dropdown-toggle',true).first();
5493 if(this.hideTrigger){
5494 this.trigger.setDisplayed(false);
5496 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
5500 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
5503 //this.trigger.addClassOnOver('x-form-trigger-over');
5504 //this.trigger.addClassOnClick('x-form-trigger-click');
5507 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
5512 initTrigger : function(){
5517 onDestroy : function(){
5519 this.trigger.removeAllListeners();
5520 // this.trigger.remove();
5523 // this.wrap.remove();
5525 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
5529 onFocus : function(){
5530 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
5533 this.wrap.addClass('x-trigger-wrap-focus');
5534 this.mimicing = true;
5535 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
5536 if(this.monitorTab){
5537 this.el.on("keydown", this.checkTab, this);
5544 checkTab : function(e){
5545 if(e.getKey() == e.TAB){
5551 onBlur : function(){
5556 mimicBlur : function(e, t){
5558 if(!this.wrap.contains(t) && this.validateBlur()){
5565 triggerBlur : function(){
5566 this.mimicing = false;
5567 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
5568 if(this.monitorTab){
5569 this.el.un("keydown", this.checkTab, this);
5571 //this.wrap.removeClass('x-trigger-wrap-focus');
5572 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
5576 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
5577 validateBlur : function(e, t){
5582 onDisable : function(){
5583 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5585 // this.wrap.addClass('x-item-disabled');
5590 onEnable : function(){
5591 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5593 // this.el.removeClass('x-item-disabled');
5598 onShow : function(){
5599 var ae = this.getActionEl();
5602 ae.dom.style.display = '';
5603 ae.dom.style.visibility = 'visible';
5609 onHide : function(){
5610 var ae = this.getActionEl();
5611 ae.dom.style.display = 'none';
5615 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5616 * by an implementing function.
5618 * @param {EventObject} e
5620 onTriggerClick : Roo.emptyFn
5624 * Ext JS Library 1.1.1
5625 * Copyright(c) 2006-2007, Ext JS, LLC.
5627 * Originally Released Under LGPL - original licence link has changed is not relivant.
5630 * <script type="text/javascript">
5635 * @class Roo.data.SortTypes
5637 * Defines the default sorting (casting?) comparison functions used when sorting data.
5639 Roo.data.SortTypes = {
5641 * Default sort that does nothing
5642 * @param {Mixed} s The value being converted
5643 * @return {Mixed} The comparison value
5650 * The regular expression used to strip tags
5654 stripTagsRE : /<\/?[^>]+>/gi,
5657 * Strips all HTML tags to sort on text only
5658 * @param {Mixed} s The value being converted
5659 * @return {String} The comparison value
5661 asText : function(s){
5662 return String(s).replace(this.stripTagsRE, "");
5666 * Strips all HTML tags to sort on text only - Case insensitive
5667 * @param {Mixed} s The value being converted
5668 * @return {String} The comparison value
5670 asUCText : function(s){
5671 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5675 * Case insensitive string
5676 * @param {Mixed} s The value being converted
5677 * @return {String} The comparison value
5679 asUCString : function(s) {
5680 return String(s).toUpperCase();
5685 * @param {Mixed} s The value being converted
5686 * @return {Number} The comparison value
5688 asDate : function(s) {
5692 if(s instanceof Date){
5695 return Date.parse(String(s));
5700 * @param {Mixed} s The value being converted
5701 * @return {Float} The comparison value
5703 asFloat : function(s) {
5704 var val = parseFloat(String(s).replace(/,/g, ""));
5705 if(isNaN(val)) val = 0;
5711 * @param {Mixed} s The value being converted
5712 * @return {Number} The comparison value
5714 asInt : function(s) {
5715 var val = parseInt(String(s).replace(/,/g, ""));
5716 if(isNaN(val)) val = 0;
5721 * Ext JS Library 1.1.1
5722 * Copyright(c) 2006-2007, Ext JS, LLC.
5724 * Originally Released Under LGPL - original licence link has changed is not relivant.
5727 * <script type="text/javascript">
5731 * @class Roo.data.Record
5732 * Instances of this class encapsulate both record <em>definition</em> information, and record
5733 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5734 * to access Records cached in an {@link Roo.data.Store} object.<br>
5736 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5737 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5740 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5742 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5743 * {@link #create}. The parameters are the same.
5744 * @param {Array} data An associative Array of data values keyed by the field name.
5745 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5746 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5747 * not specified an integer id is generated.
5749 Roo.data.Record = function(data, id){
5750 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5755 * Generate a constructor for a specific record layout.
5756 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5757 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5758 * Each field definition object may contain the following properties: <ul>
5759 * <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,
5760 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5761 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5762 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5763 * is being used, then this is a string containing the javascript expression to reference the data relative to
5764 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5765 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5766 * this may be omitted.</p></li>
5767 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5768 * <ul><li>auto (Default, implies no conversion)</li>
5773 * <li>date</li></ul></p></li>
5774 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5775 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5776 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5777 * by the Reader into an object that will be stored in the Record. It is passed the
5778 * following parameters:<ul>
5779 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5781 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5783 * <br>usage:<br><pre><code>
5784 var TopicRecord = Roo.data.Record.create(
5785 {name: 'title', mapping: 'topic_title'},
5786 {name: 'author', mapping: 'username'},
5787 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5788 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5789 {name: 'lastPoster', mapping: 'user2'},
5790 {name: 'excerpt', mapping: 'post_text'}
5793 var myNewRecord = new TopicRecord({
5794 title: 'Do my job please',
5797 lastPost: new Date(),
5798 lastPoster: 'Animal',
5799 excerpt: 'No way dude!'
5801 myStore.add(myNewRecord);
5806 Roo.data.Record.create = function(o){
5808 f.superclass.constructor.apply(this, arguments);
5810 Roo.extend(f, Roo.data.Record);
5811 var p = f.prototype;
5812 p.fields = new Roo.util.MixedCollection(false, function(field){
5815 for(var i = 0, len = o.length; i < len; i++){
5816 p.fields.add(new Roo.data.Field(o[i]));
5818 f.getField = function(name){
5819 return p.fields.get(name);
5824 Roo.data.Record.AUTO_ID = 1000;
5825 Roo.data.Record.EDIT = 'edit';
5826 Roo.data.Record.REJECT = 'reject';
5827 Roo.data.Record.COMMIT = 'commit';
5829 Roo.data.Record.prototype = {
5831 * Readonly flag - true if this record has been modified.
5840 join : function(store){
5845 * Set the named field to the specified value.
5846 * @param {String} name The name of the field to set.
5847 * @param {Object} value The value to set the field to.
5849 set : function(name, value){
5850 if(this.data[name] == value){
5857 if(typeof this.modified[name] == 'undefined'){
5858 this.modified[name] = this.data[name];
5860 this.data[name] = value;
5861 if(!this.editing && this.store){
5862 this.store.afterEdit(this);
5867 * Get the value of the named field.
5868 * @param {String} name The name of the field to get the value of.
5869 * @return {Object} The value of the field.
5871 get : function(name){
5872 return this.data[name];
5876 beginEdit : function(){
5877 this.editing = true;
5882 cancelEdit : function(){
5883 this.editing = false;
5884 delete this.modified;
5888 endEdit : function(){
5889 this.editing = false;
5890 if(this.dirty && this.store){
5891 this.store.afterEdit(this);
5896 * Usually called by the {@link Roo.data.Store} which owns the Record.
5897 * Rejects all changes made to the Record since either creation, or the last commit operation.
5898 * Modified fields are reverted to their original values.
5900 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5901 * of reject operations.
5903 reject : function(){
5904 var m = this.modified;
5906 if(typeof m[n] != "function"){
5907 this.data[n] = m[n];
5911 delete this.modified;
5912 this.editing = false;
5914 this.store.afterReject(this);
5919 * Usually called by the {@link Roo.data.Store} which owns the Record.
5920 * Commits all changes made to the Record since either creation, or the last commit operation.
5922 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5923 * of commit operations.
5925 commit : function(){
5927 delete this.modified;
5928 this.editing = false;
5930 this.store.afterCommit(this);
5935 hasError : function(){
5936 return this.error != null;
5940 clearError : function(){
5945 * Creates a copy of this record.
5946 * @param {String} id (optional) A new record id if you don't want to use this record's id
5949 copy : function(newId) {
5950 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
5954 * Ext JS Library 1.1.1
5955 * Copyright(c) 2006-2007, Ext JS, LLC.
5957 * Originally Released Under LGPL - original licence link has changed is not relivant.
5960 * <script type="text/javascript">
5966 * @class Roo.data.Store
5967 * @extends Roo.util.Observable
5968 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
5969 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
5971 * 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
5972 * has no knowledge of the format of the data returned by the Proxy.<br>
5974 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
5975 * instances from the data object. These records are cached and made available through accessor functions.
5977 * Creates a new Store.
5978 * @param {Object} config A config object containing the objects needed for the Store to access data,
5979 * and read the data into Records.
5981 Roo.data.Store = function(config){
5982 this.data = new Roo.util.MixedCollection(false);
5983 this.data.getKey = function(o){
5986 this.baseParams = {};
5993 "multisort" : "_multisort"
5996 if(config && config.data){
5997 this.inlineData = config.data;
6001 Roo.apply(this, config);
6003 if(this.reader){ // reader passed
6004 this.reader = Roo.factory(this.reader, Roo.data);
6005 this.reader.xmodule = this.xmodule || false;
6006 if(!this.recordType){
6007 this.recordType = this.reader.recordType;
6009 if(this.reader.onMetaChange){
6010 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6014 if(this.recordType){
6015 this.fields = this.recordType.prototype.fields;
6021 * @event datachanged
6022 * Fires when the data cache has changed, and a widget which is using this Store
6023 * as a Record cache should refresh its view.
6024 * @param {Store} this
6029 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6030 * @param {Store} this
6031 * @param {Object} meta The JSON metadata
6036 * Fires when Records have been added to the Store
6037 * @param {Store} this
6038 * @param {Roo.data.Record[]} records The array of Records added
6039 * @param {Number} index The index at which the record(s) were added
6044 * Fires when a Record has been removed from the Store
6045 * @param {Store} this
6046 * @param {Roo.data.Record} record The Record that was removed
6047 * @param {Number} index The index at which the record was removed
6052 * Fires when a Record has been updated
6053 * @param {Store} this
6054 * @param {Roo.data.Record} record The Record that was updated
6055 * @param {String} operation The update operation being performed. Value may be one of:
6057 Roo.data.Record.EDIT
6058 Roo.data.Record.REJECT
6059 Roo.data.Record.COMMIT
6065 * Fires when the data cache has been cleared.
6066 * @param {Store} this
6071 * Fires before a request is made for a new data object. If the beforeload handler returns false
6072 * the load action will be canceled.
6073 * @param {Store} this
6074 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6078 * @event beforeloadadd
6079 * Fires after a new set of Records has been loaded.
6080 * @param {Store} this
6081 * @param {Roo.data.Record[]} records The Records that were loaded
6082 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6084 beforeloadadd : true,
6087 * Fires after a new set of Records has been loaded, before they are added to the store.
6088 * @param {Store} this
6089 * @param {Roo.data.Record[]} records The Records that were loaded
6090 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6091 * @params {Object} return from reader
6095 * @event loadexception
6096 * Fires if an exception occurs in the Proxy during loading.
6097 * Called with the signature of the Proxy's "loadexception" event.
6098 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6101 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6102 * @param {Object} load options
6103 * @param {Object} jsonData from your request (normally this contains the Exception)
6105 loadexception : true
6109 this.proxy = Roo.factory(this.proxy, Roo.data);
6110 this.proxy.xmodule = this.xmodule || false;
6111 this.relayEvents(this.proxy, ["loadexception"]);
6113 this.sortToggle = {};
6114 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6116 Roo.data.Store.superclass.constructor.call(this);
6118 if(this.inlineData){
6119 this.loadData(this.inlineData);
6120 delete this.inlineData;
6124 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6126 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6127 * without a remote query - used by combo/forms at present.
6131 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6134 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6137 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6138 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6141 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6142 * on any HTTP request
6145 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6148 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6152 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6153 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
6158 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
6159 * loaded or when a record is removed. (defaults to false).
6161 pruneModifiedRecords : false,
6167 * Add Records to the Store and fires the add event.
6168 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6170 add : function(records){
6171 records = [].concat(records);
6172 for(var i = 0, len = records.length; i < len; i++){
6173 records[i].join(this);
6175 var index = this.data.length;
6176 this.data.addAll(records);
6177 this.fireEvent("add", this, records, index);
6181 * Remove a Record from the Store and fires the remove event.
6182 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
6184 remove : function(record){
6185 var index = this.data.indexOf(record);
6186 this.data.removeAt(index);
6187 if(this.pruneModifiedRecords){
6188 this.modified.remove(record);
6190 this.fireEvent("remove", this, record, index);
6194 * Remove all Records from the Store and fires the clear event.
6196 removeAll : function(){
6198 if(this.pruneModifiedRecords){
6201 this.fireEvent("clear", this);
6205 * Inserts Records to the Store at the given index and fires the add event.
6206 * @param {Number} index The start index at which to insert the passed Records.
6207 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6209 insert : function(index, records){
6210 records = [].concat(records);
6211 for(var i = 0, len = records.length; i < len; i++){
6212 this.data.insert(index, records[i]);
6213 records[i].join(this);
6215 this.fireEvent("add", this, records, index);
6219 * Get the index within the cache of the passed Record.
6220 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
6221 * @return {Number} The index of the passed Record. Returns -1 if not found.
6223 indexOf : function(record){
6224 return this.data.indexOf(record);
6228 * Get the index within the cache of the Record with the passed id.
6229 * @param {String} id The id of the Record to find.
6230 * @return {Number} The index of the Record. Returns -1 if not found.
6232 indexOfId : function(id){
6233 return this.data.indexOfKey(id);
6237 * Get the Record with the specified id.
6238 * @param {String} id The id of the Record to find.
6239 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
6241 getById : function(id){
6242 return this.data.key(id);
6246 * Get the Record at the specified index.
6247 * @param {Number} index The index of the Record to find.
6248 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
6250 getAt : function(index){
6251 return this.data.itemAt(index);
6255 * Returns a range of Records between specified indices.
6256 * @param {Number} startIndex (optional) The starting index (defaults to 0)
6257 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
6258 * @return {Roo.data.Record[]} An array of Records
6260 getRange : function(start, end){
6261 return this.data.getRange(start, end);
6265 storeOptions : function(o){
6266 o = Roo.apply({}, o);
6269 this.lastOptions = o;
6273 * Loads the Record cache from the configured Proxy using the configured Reader.
6275 * If using remote paging, then the first load call must specify the <em>start</em>
6276 * and <em>limit</em> properties in the options.params property to establish the initial
6277 * position within the dataset, and the number of Records to cache on each read from the Proxy.
6279 * <strong>It is important to note that for remote data sources, loading is asynchronous,
6280 * and this call will return before the new data has been loaded. Perform any post-processing
6281 * in a callback function, or in a "load" event handler.</strong>
6283 * @param {Object} options An object containing properties which control loading options:<ul>
6284 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
6285 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
6286 * passed the following arguments:<ul>
6287 * <li>r : Roo.data.Record[]</li>
6288 * <li>options: Options object from the load call</li>
6289 * <li>success: Boolean success indicator</li></ul></li>
6290 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
6291 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
6294 load : function(options){
6295 options = options || {};
6296 if(this.fireEvent("beforeload", this, options) !== false){
6297 this.storeOptions(options);
6298 var p = Roo.apply(options.params || {}, this.baseParams);
6299 // if meta was not loaded from remote source.. try requesting it.
6300 if (!this.reader.metaFromRemote) {
6303 if(this.sortInfo && this.remoteSort){
6304 var pn = this.paramNames;
6305 p[pn["sort"]] = this.sortInfo.field;
6306 p[pn["dir"]] = this.sortInfo.direction;
6308 if (this.multiSort) {
6309 var pn = this.paramNames;
6310 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
6313 this.proxy.load(p, this.reader, this.loadRecords, this, options);
6318 * Reloads the Record cache from the configured Proxy using the configured Reader and
6319 * the options from the last load operation performed.
6320 * @param {Object} options (optional) An object containing properties which may override the options
6321 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
6322 * the most recently used options are reused).
6324 reload : function(options){
6325 this.load(Roo.applyIf(options||{}, this.lastOptions));
6329 // Called as a callback by the Reader during a load operation.
6330 loadRecords : function(o, options, success){
6331 if(!o || success === false){
6332 if(success !== false){
6333 this.fireEvent("load", this, [], options, o);
6335 if(options.callback){
6336 options.callback.call(options.scope || this, [], options, false);
6340 // if data returned failure - throw an exception.
6341 if (o.success === false) {
6342 // show a message if no listener is registered.
6343 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
6344 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
6346 // loadmask wil be hooked into this..
6347 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
6350 var r = o.records, t = o.totalRecords || r.length;
6352 this.fireEvent("beforeloadadd", this, r, options, o);
6354 if(!options || options.add !== true){
6355 if(this.pruneModifiedRecords){
6358 for(var i = 0, len = r.length; i < len; i++){
6362 this.data = this.snapshot;
6363 delete this.snapshot;
6366 this.data.addAll(r);
6367 this.totalLength = t;
6369 this.fireEvent("datachanged", this);
6371 this.totalLength = Math.max(t, this.data.length+r.length);
6374 this.fireEvent("load", this, r, options, o);
6375 if(options.callback){
6376 options.callback.call(options.scope || this, r, options, true);
6382 * Loads data from a passed data block. A Reader which understands the format of the data
6383 * must have been configured in the constructor.
6384 * @param {Object} data The data block from which to read the Records. The format of the data expected
6385 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
6386 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
6388 loadData : function(o, append){
6389 var r = this.reader.readRecords(o);
6390 this.loadRecords(r, {add: append}, true);
6394 * Gets the number of cached records.
6396 * <em>If using paging, this may not be the total size of the dataset. If the data object
6397 * used by the Reader contains the dataset size, then the getTotalCount() function returns
6398 * the data set size</em>
6400 getCount : function(){
6401 return this.data.length || 0;
6405 * Gets the total number of records in the dataset as returned by the server.
6407 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
6408 * the dataset size</em>
6410 getTotalCount : function(){
6411 return this.totalLength || 0;
6415 * Returns the sort state of the Store as an object with two properties:
6417 field {String} The name of the field by which the Records are sorted
6418 direction {String} The sort order, "ASC" or "DESC"
6421 getSortState : function(){
6422 return this.sortInfo;
6426 applySort : function(){
6427 if(this.sortInfo && !this.remoteSort){
6428 var s = this.sortInfo, f = s.field;
6429 var st = this.fields.get(f).sortType;
6430 var fn = function(r1, r2){
6431 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
6432 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
6434 this.data.sort(s.direction, fn);
6435 if(this.snapshot && this.snapshot != this.data){
6436 this.snapshot.sort(s.direction, fn);
6442 * Sets the default sort column and order to be used by the next load operation.
6443 * @param {String} fieldName The name of the field to sort by.
6444 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6446 setDefaultSort : function(field, dir){
6447 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
6452 * If remote sorting is used, the sort is performed on the server, and the cache is
6453 * reloaded. If local sorting is used, the cache is sorted internally.
6454 * @param {String} fieldName The name of the field to sort by.
6455 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6457 sort : function(fieldName, dir){
6458 var f = this.fields.get(fieldName);
6460 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
6462 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
6463 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
6468 this.sortToggle[f.name] = dir;
6469 this.sortInfo = {field: f.name, direction: dir};
6470 if(!this.remoteSort){
6472 this.fireEvent("datachanged", this);
6474 this.load(this.lastOptions);
6479 * Calls the specified function for each of the Records in the cache.
6480 * @param {Function} fn The function to call. The Record is passed as the first parameter.
6481 * Returning <em>false</em> aborts and exits the iteration.
6482 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
6484 each : function(fn, scope){
6485 this.data.each(fn, scope);
6489 * Gets all records modified since the last commit. Modified records are persisted across load operations
6490 * (e.g., during paging).
6491 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
6493 getModifiedRecords : function(){
6494 return this.modified;
6498 createFilterFn : function(property, value, anyMatch){
6499 if(!value.exec){ // not a regex
6500 value = String(value);
6501 if(value.length == 0){
6504 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
6507 return value.test(r.data[property]);
6512 * Sums the value of <i>property</i> for each record between start and end and returns the result.
6513 * @param {String} property A field on your records
6514 * @param {Number} start The record index to start at (defaults to 0)
6515 * @param {Number} end The last record index to include (defaults to length - 1)
6516 * @return {Number} The sum
6518 sum : function(property, start, end){
6519 var rs = this.data.items, v = 0;
6521 end = (end || end === 0) ? end : rs.length-1;
6523 for(var i = start; i <= end; i++){
6524 v += (rs[i].data[property] || 0);
6530 * Filter the records by a specified property.
6531 * @param {String} field A field on your records
6532 * @param {String/RegExp} value Either a string that the field
6533 * should start with or a RegExp to test against the field
6534 * @param {Boolean} anyMatch True to match any part not just the beginning
6536 filter : function(property, value, anyMatch){
6537 var fn = this.createFilterFn(property, value, anyMatch);
6538 return fn ? this.filterBy(fn) : this.clearFilter();
6542 * Filter by a function. The specified function will be called with each
6543 * record in this data source. If the function returns true the record is included,
6544 * otherwise it is filtered.
6545 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6546 * @param {Object} scope (optional) The scope of the function (defaults to this)
6548 filterBy : function(fn, scope){
6549 this.snapshot = this.snapshot || this.data;
6550 this.data = this.queryBy(fn, scope||this);
6551 this.fireEvent("datachanged", this);
6555 * Query the records by a specified property.
6556 * @param {String} field A field on your records
6557 * @param {String/RegExp} value Either a string that the field
6558 * should start with or a RegExp to test against the field
6559 * @param {Boolean} anyMatch True to match any part not just the beginning
6560 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6562 query : function(property, value, anyMatch){
6563 var fn = this.createFilterFn(property, value, anyMatch);
6564 return fn ? this.queryBy(fn) : this.data.clone();
6568 * Query by a function. The specified function will be called with each
6569 * record in this data source. If the function returns true the record is included
6571 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6572 * @param {Object} scope (optional) The scope of the function (defaults to this)
6573 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6575 queryBy : function(fn, scope){
6576 var data = this.snapshot || this.data;
6577 return data.filterBy(fn, scope||this);
6581 * Collects unique values for a particular dataIndex from this store.
6582 * @param {String} dataIndex The property to collect
6583 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
6584 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6585 * @return {Array} An array of the unique values
6587 collect : function(dataIndex, allowNull, bypassFilter){
6588 var d = (bypassFilter === true && this.snapshot) ?
6589 this.snapshot.items : this.data.items;
6590 var v, sv, r = [], l = {};
6591 for(var i = 0, len = d.length; i < len; i++){
6592 v = d[i].data[dataIndex];
6594 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6603 * Revert to a view of the Record cache with no filtering applied.
6604 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6606 clearFilter : function(suppressEvent){
6607 if(this.snapshot && this.snapshot != this.data){
6608 this.data = this.snapshot;
6609 delete this.snapshot;
6610 if(suppressEvent !== true){
6611 this.fireEvent("datachanged", this);
6617 afterEdit : function(record){
6618 if(this.modified.indexOf(record) == -1){
6619 this.modified.push(record);
6621 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6625 afterReject : function(record){
6626 this.modified.remove(record);
6627 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6631 afterCommit : function(record){
6632 this.modified.remove(record);
6633 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6637 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6638 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6640 commitChanges : function(){
6641 var m = this.modified.slice(0);
6643 for(var i = 0, len = m.length; i < len; i++){
6649 * Cancel outstanding changes on all changed records.
6651 rejectChanges : function(){
6652 var m = this.modified.slice(0);
6654 for(var i = 0, len = m.length; i < len; i++){
6659 onMetaChange : function(meta, rtype, o){
6660 this.recordType = rtype;
6661 this.fields = rtype.prototype.fields;
6662 delete this.snapshot;
6663 this.sortInfo = meta.sortInfo || this.sortInfo;
6665 this.fireEvent('metachange', this, this.reader.meta);
6669 * Ext JS Library 1.1.1
6670 * Copyright(c) 2006-2007, Ext JS, LLC.
6672 * Originally Released Under LGPL - original licence link has changed is not relivant.
6675 * <script type="text/javascript">
6679 * @class Roo.data.SimpleStore
6680 * @extends Roo.data.Store
6681 * Small helper class to make creating Stores from Array data easier.
6682 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6683 * @cfg {Array} fields An array of field definition objects, or field name strings.
6684 * @cfg {Array} data The multi-dimensional array of data
6686 * @param {Object} config
6688 Roo.data.SimpleStore = function(config){
6689 Roo.data.SimpleStore.superclass.constructor.call(this, {
6691 reader: new Roo.data.ArrayReader({
6694 Roo.data.Record.create(config.fields)
6696 proxy : new Roo.data.MemoryProxy(config.data)
6700 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6702 * Ext JS Library 1.1.1
6703 * Copyright(c) 2006-2007, Ext JS, LLC.
6705 * Originally Released Under LGPL - original licence link has changed is not relivant.
6708 * <script type="text/javascript">
6713 * @extends Roo.data.Store
6714 * @class Roo.data.JsonStore
6715 * Small helper class to make creating Stores for JSON data easier. <br/>
6717 var store = new Roo.data.JsonStore({
6718 url: 'get-images.php',
6720 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6723 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6724 * JsonReader and HttpProxy (unless inline data is provided).</b>
6725 * @cfg {Array} fields An array of field definition objects, or field name strings.
6727 * @param {Object} config
6729 Roo.data.JsonStore = function(c){
6730 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6731 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6732 reader: new Roo.data.JsonReader(c, c.fields)
6735 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6737 * Ext JS Library 1.1.1
6738 * Copyright(c) 2006-2007, Ext JS, LLC.
6740 * Originally Released Under LGPL - original licence link has changed is not relivant.
6743 * <script type="text/javascript">
6747 Roo.data.Field = function(config){
6748 if(typeof config == "string"){
6749 config = {name: config};
6751 Roo.apply(this, config);
6757 var st = Roo.data.SortTypes;
6758 // named sortTypes are supported, here we look them up
6759 if(typeof this.sortType == "string"){
6760 this.sortType = st[this.sortType];
6763 // set default sortType for strings and dates
6767 this.sortType = st.asUCString;
6770 this.sortType = st.asDate;
6773 this.sortType = st.none;
6778 var stripRe = /[\$,%]/g;
6780 // prebuilt conversion function for this field, instead of
6781 // switching every time we're reading a value
6783 var cv, dateFormat = this.dateFormat;
6788 cv = function(v){ return v; };
6791 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6795 return v !== undefined && v !== null && v !== '' ?
6796 parseInt(String(v).replace(stripRe, ""), 10) : '';
6801 return v !== undefined && v !== null && v !== '' ?
6802 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6807 cv = function(v){ return v === true || v === "true" || v == 1; };
6814 if(v instanceof Date){
6818 if(dateFormat == "timestamp"){
6819 return new Date(v*1000);
6821 return Date.parseDate(v, dateFormat);
6823 var parsed = Date.parse(v);
6824 return parsed ? new Date(parsed) : null;
6833 Roo.data.Field.prototype = {
6841 * Ext JS Library 1.1.1
6842 * Copyright(c) 2006-2007, Ext JS, LLC.
6844 * Originally Released Under LGPL - original licence link has changed is not relivant.
6847 * <script type="text/javascript">
6850 // Base class for reading structured data from a data source. This class is intended to be
6851 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6854 * @class Roo.data.DataReader
6855 * Base class for reading structured data from a data source. This class is intended to be
6856 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6859 Roo.data.DataReader = function(meta, recordType){
6863 this.recordType = recordType instanceof Array ?
6864 Roo.data.Record.create(recordType) : recordType;
6867 Roo.data.DataReader.prototype = {
6869 * Create an empty record
6870 * @param {Object} data (optional) - overlay some values
6871 * @return {Roo.data.Record} record created.
6873 newRow : function(d) {
6875 this.recordType.prototype.fields.each(function(c) {
6877 case 'int' : da[c.name] = 0; break;
6878 case 'date' : da[c.name] = new Date(); break;
6879 case 'float' : da[c.name] = 0.0; break;
6880 case 'boolean' : da[c.name] = false; break;
6881 default : da[c.name] = ""; break;
6885 return new this.recordType(Roo.apply(da, d));
6890 * Ext JS Library 1.1.1
6891 * Copyright(c) 2006-2007, Ext JS, LLC.
6893 * Originally Released Under LGPL - original licence link has changed is not relivant.
6896 * <script type="text/javascript">
6900 * @class Roo.data.DataProxy
6901 * @extends Roo.data.Observable
6902 * This class is an abstract base class for implementations which provide retrieval of
6903 * unformatted data objects.<br>
6905 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6906 * (of the appropriate type which knows how to parse the data object) to provide a block of
6907 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6909 * Custom implementations must implement the load method as described in
6910 * {@link Roo.data.HttpProxy#load}.
6912 Roo.data.DataProxy = function(){
6916 * Fires before a network request is made to retrieve a data object.
6917 * @param {Object} This DataProxy object.
6918 * @param {Object} params The params parameter to the load function.
6923 * Fires before the load method's callback is called.
6924 * @param {Object} This DataProxy object.
6925 * @param {Object} o The data object.
6926 * @param {Object} arg The callback argument object passed to the load function.
6930 * @event loadexception
6931 * Fires if an Exception occurs during data retrieval.
6932 * @param {Object} This DataProxy object.
6933 * @param {Object} o The data object.
6934 * @param {Object} arg The callback argument object passed to the load function.
6935 * @param {Object} e The Exception.
6937 loadexception : true
6939 Roo.data.DataProxy.superclass.constructor.call(this);
6942 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
6945 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
6949 * Ext JS Library 1.1.1
6950 * Copyright(c) 2006-2007, Ext JS, LLC.
6952 * Originally Released Under LGPL - original licence link has changed is not relivant.
6955 * <script type="text/javascript">
6958 * @class Roo.data.MemoryProxy
6959 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
6960 * to the Reader when its load method is called.
6962 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
6964 Roo.data.MemoryProxy = function(data){
6968 Roo.data.MemoryProxy.superclass.constructor.call(this);
6972 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
6974 * Load data from the requested source (in this case an in-memory
6975 * data object passed to the constructor), read the data object into
6976 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
6977 * process that block using the passed callback.
6978 * @param {Object} params This parameter is not used by the MemoryProxy class.
6979 * @param {Roo.data.DataReader} reader The Reader object which converts the data
6980 * object into a block of Roo.data.Records.
6981 * @param {Function} callback The function into which to pass the block of Roo.data.records.
6982 * The function must be passed <ul>
6983 * <li>The Record block object</li>
6984 * <li>The "arg" argument from the load function</li>
6985 * <li>A boolean success indicator</li>
6987 * @param {Object} scope The scope in which to call the callback
6988 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6990 load : function(params, reader, callback, scope, arg){
6991 params = params || {};
6994 result = reader.readRecords(this.data);
6996 this.fireEvent("loadexception", this, arg, null, e);
6997 callback.call(scope, null, arg, false);
7000 callback.call(scope, result, arg, true);
7004 update : function(params, records){
7009 * Ext JS Library 1.1.1
7010 * Copyright(c) 2006-2007, Ext JS, LLC.
7012 * Originally Released Under LGPL - original licence link has changed is not relivant.
7015 * <script type="text/javascript">
7018 * @class Roo.data.HttpProxy
7019 * @extends Roo.data.DataProxy
7020 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7021 * configured to reference a certain URL.<br><br>
7023 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7024 * from which the running page was served.<br><br>
7026 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7028 * Be aware that to enable the browser to parse an XML document, the server must set
7029 * the Content-Type header in the HTTP response to "text/xml".
7031 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7032 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7033 * will be used to make the request.
7035 Roo.data.HttpProxy = function(conn){
7036 Roo.data.HttpProxy.superclass.constructor.call(this);
7037 // is conn a conn config or a real conn?
7039 this.useAjax = !conn || !conn.events;
7043 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7044 // thse are take from connection...
7047 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7050 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7051 * extra parameters to each request made by this object. (defaults to undefined)
7054 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7055 * to each request made by this object. (defaults to undefined)
7058 * @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)
7061 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7064 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7070 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7074 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7075 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7076 * a finer-grained basis than the DataProxy events.
7078 getConnection : function(){
7079 return this.useAjax ? Roo.Ajax : this.conn;
7083 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7084 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7085 * process that block using the passed callback.
7086 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7087 * for the request to the remote server.
7088 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7089 * object into a block of Roo.data.Records.
7090 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7091 * The function must be passed <ul>
7092 * <li>The Record block object</li>
7093 * <li>The "arg" argument from the load function</li>
7094 * <li>A boolean success indicator</li>
7096 * @param {Object} scope The scope in which to call the callback
7097 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7099 load : function(params, reader, callback, scope, arg){
7100 if(this.fireEvent("beforeload", this, params) !== false){
7102 params : params || {},
7104 callback : callback,
7109 callback : this.loadResponse,
7113 Roo.applyIf(o, this.conn);
7114 if(this.activeRequest){
7115 Roo.Ajax.abort(this.activeRequest);
7117 this.activeRequest = Roo.Ajax.request(o);
7119 this.conn.request(o);
7122 callback.call(scope||this, null, arg, false);
7127 loadResponse : function(o, success, response){
7128 delete this.activeRequest;
7130 this.fireEvent("loadexception", this, o, response);
7131 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7136 result = o.reader.read(response);
7138 this.fireEvent("loadexception", this, o, response, e);
7139 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7143 this.fireEvent("load", this, o, o.request.arg);
7144 o.request.callback.call(o.request.scope, result, o.request.arg, true);
7148 update : function(dataSet){
7153 updateResponse : function(dataSet){
7158 * Ext JS Library 1.1.1
7159 * Copyright(c) 2006-2007, Ext JS, LLC.
7161 * Originally Released Under LGPL - original licence link has changed is not relivant.
7164 * <script type="text/javascript">
7168 * @class Roo.data.ScriptTagProxy
7169 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
7170 * other than the originating domain of the running page.<br><br>
7172 * <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
7173 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
7175 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
7176 * source code that is used as the source inside a <script> tag.<br><br>
7178 * In order for the browser to process the returned data, the server must wrap the data object
7179 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
7180 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
7181 * depending on whether the callback name was passed:
7184 boolean scriptTag = false;
7185 String cb = request.getParameter("callback");
7188 response.setContentType("text/javascript");
7190 response.setContentType("application/x-json");
7192 Writer out = response.getWriter();
7194 out.write(cb + "(");
7196 out.print(dataBlock.toJsonString());
7203 * @param {Object} config A configuration object.
7205 Roo.data.ScriptTagProxy = function(config){
7206 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
7207 Roo.apply(this, config);
7208 this.head = document.getElementsByTagName("head")[0];
7211 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
7213 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
7215 * @cfg {String} url The URL from which to request the data object.
7218 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
7222 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
7223 * the server the name of the callback function set up by the load call to process the returned data object.
7224 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
7225 * javascript output which calls this named function passing the data object as its only parameter.
7227 callbackParam : "callback",
7229 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
7230 * name to the request.
7235 * Load data from the configured URL, read the data object into
7236 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7237 * process that block using the passed callback.
7238 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7239 * for the request to the remote server.
7240 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7241 * object into a block of Roo.data.Records.
7242 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7243 * The function must be passed <ul>
7244 * <li>The Record block object</li>
7245 * <li>The "arg" argument from the load function</li>
7246 * <li>A boolean success indicator</li>
7248 * @param {Object} scope The scope in which to call the callback
7249 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7251 load : function(params, reader, callback, scope, arg){
7252 if(this.fireEvent("beforeload", this, params) !== false){
7254 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
7257 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
7259 url += "&_dc=" + (new Date().getTime());
7261 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
7264 cb : "stcCallback"+transId,
7265 scriptId : "stcScript"+transId,
7269 callback : callback,
7275 window[trans.cb] = function(o){
7276 conn.handleResponse(o, trans);
7279 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
7281 if(this.autoAbort !== false){
7285 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
7287 var script = document.createElement("script");
7288 script.setAttribute("src", url);
7289 script.setAttribute("type", "text/javascript");
7290 script.setAttribute("id", trans.scriptId);
7291 this.head.appendChild(script);
7295 callback.call(scope||this, null, arg, false);
7300 isLoading : function(){
7301 return this.trans ? true : false;
7305 * Abort the current server request.
7308 if(this.isLoading()){
7309 this.destroyTrans(this.trans);
7314 destroyTrans : function(trans, isLoaded){
7315 this.head.removeChild(document.getElementById(trans.scriptId));
7316 clearTimeout(trans.timeoutId);
7318 window[trans.cb] = undefined;
7320 delete window[trans.cb];
7323 // if hasn't been loaded, wait for load to remove it to prevent script error
7324 window[trans.cb] = function(){
7325 window[trans.cb] = undefined;
7327 delete window[trans.cb];
7334 handleResponse : function(o, trans){
7336 this.destroyTrans(trans, true);
7339 result = trans.reader.readRecords(o);
7341 this.fireEvent("loadexception", this, o, trans.arg, e);
7342 trans.callback.call(trans.scope||window, null, trans.arg, false);
7345 this.fireEvent("load", this, o, trans.arg);
7346 trans.callback.call(trans.scope||window, result, trans.arg, true);
7350 handleFailure : function(trans){
7352 this.destroyTrans(trans, false);
7353 this.fireEvent("loadexception", this, null, trans.arg);
7354 trans.callback.call(trans.scope||window, null, trans.arg, false);
7358 * Ext JS Library 1.1.1
7359 * Copyright(c) 2006-2007, Ext JS, LLC.
7361 * Originally Released Under LGPL - original licence link has changed is not relivant.
7364 * <script type="text/javascript">
7368 * @class Roo.data.JsonReader
7369 * @extends Roo.data.DataReader
7370 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
7371 * based on mappings in a provided Roo.data.Record constructor.
7373 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
7374 * in the reply previously.
7379 var RecordDef = Roo.data.Record.create([
7380 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
7381 {name: 'occupation'} // This field will use "occupation" as the mapping.
7383 var myReader = new Roo.data.JsonReader({
7384 totalProperty: "results", // The property which contains the total dataset size (optional)
7385 root: "rows", // The property which contains an Array of row objects
7386 id: "id" // The property within each row object that provides an ID for the record (optional)
7390 * This would consume a JSON file like this:
7392 { 'results': 2, 'rows': [
7393 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
7394 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
7397 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
7398 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
7399 * paged from the remote server.
7400 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
7401 * @cfg {String} root name of the property which contains the Array of row objects.
7402 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
7404 * Create a new JsonReader
7405 * @param {Object} meta Metadata configuration options
7406 * @param {Object} recordType Either an Array of field definition objects,
7407 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
7409 Roo.data.JsonReader = function(meta, recordType){
7412 // set some defaults:
7414 totalProperty: 'total',
7415 successProperty : 'success',
7420 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
7422 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
7425 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
7426 * Used by Store query builder to append _requestMeta to params.
7429 metaFromRemote : false,
7431 * This method is only used by a DataProxy which has retrieved data from a remote server.
7432 * @param {Object} response The XHR object which contains the JSON data in its responseText.
7433 * @return {Object} data A data block which is used by an Roo.data.Store object as
7434 * a cache of Roo.data.Records.
7436 read : function(response){
7437 var json = response.responseText;
7439 var o = /* eval:var:o */ eval("("+json+")");
7441 throw {message: "JsonReader.read: Json object not found"};
7447 this.metaFromRemote = true;
7448 this.meta = o.metaData;
7449 this.recordType = Roo.data.Record.create(o.metaData.fields);
7450 this.onMetaChange(this.meta, this.recordType, o);
7452 return this.readRecords(o);
7455 // private function a store will implement
7456 onMetaChange : function(meta, recordType, o){
7463 simpleAccess: function(obj, subsc) {
7470 getJsonAccessor: function(){
7472 return function(expr) {
7474 return(re.test(expr))
7475 ? new Function("obj", "return obj." + expr)
7485 * Create a data block containing Roo.data.Records from an XML document.
7486 * @param {Object} o An object which contains an Array of row objects in the property specified
7487 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
7488 * which contains the total size of the dataset.
7489 * @return {Object} data A data block which is used by an Roo.data.Store object as
7490 * a cache of Roo.data.Records.
7492 readRecords : function(o){
7494 * After any data loads, the raw JSON data is available for further custom processing.
7498 var s = this.meta, Record = this.recordType,
7499 f = Record.prototype.fields, fi = f.items, fl = f.length;
7501 // Generate extraction functions for the totalProperty, the root, the id, and for each field
7503 if(s.totalProperty) {
7504 this.getTotal = this.getJsonAccessor(s.totalProperty);
7506 if(s.successProperty) {
7507 this.getSuccess = this.getJsonAccessor(s.successProperty);
7509 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
7511 var g = this.getJsonAccessor(s.id);
7512 this.getId = function(rec) {
7514 return (r === undefined || r === "") ? null : r;
7517 this.getId = function(){return null;};
7520 for(var jj = 0; jj < fl; jj++){
7522 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
7523 this.ef[jj] = this.getJsonAccessor(map);
7527 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
7528 if(s.totalProperty){
7529 var vt = parseInt(this.getTotal(o), 10);
7534 if(s.successProperty){
7535 var vs = this.getSuccess(o);
7536 if(vs === false || vs === 'false'){
7541 for(var i = 0; i < c; i++){
7544 var id = this.getId(n);
7545 for(var j = 0; j < fl; j++){
7547 var v = this.ef[j](n);
7549 Roo.log('missing convert for ' + f.name);
7553 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
7555 var record = new Record(values, id);
7557 records[i] = record;
7563 totalRecords : totalRecords
7568 * Ext JS Library 1.1.1
7569 * Copyright(c) 2006-2007, Ext JS, LLC.
7571 * Originally Released Under LGPL - original licence link has changed is not relivant.
7574 * <script type="text/javascript">
7578 * @class Roo.data.ArrayReader
7579 * @extends Roo.data.DataReader
7580 * Data reader class to create an Array of Roo.data.Record objects from an Array.
7581 * Each element of that Array represents a row of data fields. The
7582 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
7583 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7587 var RecordDef = Roo.data.Record.create([
7588 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7589 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7591 var myReader = new Roo.data.ArrayReader({
7592 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7596 * This would consume an Array like this:
7598 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7600 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7602 * Create a new JsonReader
7603 * @param {Object} meta Metadata configuration options.
7604 * @param {Object} recordType Either an Array of field definition objects
7605 * as specified to {@link Roo.data.Record#create},
7606 * or an {@link Roo.data.Record} object
7607 * created using {@link Roo.data.Record#create}.
7609 Roo.data.ArrayReader = function(meta, recordType){
7610 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7613 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7615 * Create a data block containing Roo.data.Records from an XML document.
7616 * @param {Object} o An Array of row objects which represents the dataset.
7617 * @return {Object} data A data block which is used by an Roo.data.Store object as
7618 * a cache of Roo.data.Records.
7620 readRecords : function(o){
7621 var sid = this.meta ? this.meta.id : null;
7622 var recordType = this.recordType, fields = recordType.prototype.fields;
7625 for(var i = 0; i < root.length; i++){
7628 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7629 for(var j = 0, jlen = fields.length; j < jlen; j++){
7630 var f = fields.items[j];
7631 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7632 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7636 var record = new recordType(values, id);
7638 records[records.length] = record;
7642 totalRecords : records.length
7651 * @class Roo.bootstrap.ComboBox
7652 * @extends Roo.bootstrap.TriggerField
7653 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7654 * @cfg {Boolean} append (true|false) default false
7656 * Create a new ComboBox.
7657 * @param {Object} config Configuration options
7659 Roo.bootstrap.ComboBox = function(config){
7660 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7664 * Fires when the dropdown list is expanded
7665 * @param {Roo.bootstrap.ComboBox} combo This combo box
7670 * Fires when the dropdown list is collapsed
7671 * @param {Roo.bootstrap.ComboBox} combo This combo box
7675 * @event beforeselect
7676 * Fires before a list item is selected. Return false to cancel the selection.
7677 * @param {Roo.bootstrap.ComboBox} combo This combo box
7678 * @param {Roo.data.Record} record The data record returned from the underlying store
7679 * @param {Number} index The index of the selected item in the dropdown list
7681 'beforeselect' : true,
7684 * Fires when a list item is selected
7685 * @param {Roo.bootstrap.ComboBox} combo This combo box
7686 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7687 * @param {Number} index The index of the selected item in the dropdown list
7691 * @event beforequery
7692 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7693 * The event object passed has these properties:
7694 * @param {Roo.bootstrap.ComboBox} combo This combo box
7695 * @param {String} query The query
7696 * @param {Boolean} forceAll true to force "all" query
7697 * @param {Boolean} cancel true to cancel the query
7698 * @param {Object} e The query event object
7700 'beforequery': true,
7703 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7704 * @param {Roo.bootstrap.ComboBox} combo This combo box
7709 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7710 * @param {Roo.bootstrap.ComboBox} combo This combo box
7711 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7716 * Fires when the remove value from the combobox array
7717 * @param {Roo.bootstrap.ComboBox} combo This combo box
7724 this.selectedIndex = -1;
7725 if(this.mode == 'local'){
7726 if(config.queryDelay === undefined){
7727 this.queryDelay = 10;
7729 if(config.minChars === undefined){
7735 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7738 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7739 * rendering into an Roo.Editor, defaults to false)
7742 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7743 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7746 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7749 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7750 * the dropdown list (defaults to undefined, with no header element)
7754 * @cfg {String/Roo.Template} tpl The template to use to render the output
7758 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7760 listWidth: undefined,
7762 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7763 * mode = 'remote' or 'text' if mode = 'local')
7765 displayField: undefined,
7767 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7768 * mode = 'remote' or 'value' if mode = 'local').
7769 * Note: use of a valueField requires the user make a selection
7770 * in order for a value to be mapped.
7772 valueField: undefined,
7776 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7777 * field's data value (defaults to the underlying DOM element's name)
7779 hiddenName: undefined,
7781 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7785 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7787 selectedClass: 'active',
7790 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7794 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7795 * anchor positions (defaults to 'tl-bl')
7797 listAlign: 'tl-bl?',
7799 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7803 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7804 * query specified by the allQuery config option (defaults to 'query')
7806 triggerAction: 'query',
7808 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7809 * (defaults to 4, does not apply if editable = false)
7813 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7814 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7818 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7819 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7823 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7824 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7828 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7829 * when editable = true (defaults to false)
7831 selectOnFocus:false,
7833 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7835 queryParam: 'query',
7837 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7838 * when mode = 'remote' (defaults to 'Loading...')
7840 loadingText: 'Loading...',
7842 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7846 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7850 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7851 * traditional select (defaults to true)
7855 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7859 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7863 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7864 * listWidth has a higher value)
7868 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7869 * allow the user to set arbitrary text into the field (defaults to false)
7871 forceSelection:false,
7873 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7874 * if typeAhead = true (defaults to 250)
7876 typeAheadDelay : 250,
7878 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7879 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7881 valueNotFoundText : undefined,
7883 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7888 * @cfg {Boolean} disableClear Disable showing of clear button.
7890 disableClear : false,
7892 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7894 alwaysQuery : false,
7897 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
7911 // element that contains real text value.. (when hidden is used..)
7914 initEvents: function(){
7917 throw "can not find store for combo";
7919 this.store = Roo.factory(this.store, Roo.data);
7923 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7926 if(this.hiddenName){
7928 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7930 this.hiddenField.dom.value =
7931 this.hiddenValue !== undefined ? this.hiddenValue :
7932 this.value !== undefined ? this.value : '';
7934 // prevent input submission
7935 this.el.dom.removeAttribute('name');
7936 this.hiddenField.dom.setAttribute('name', this.hiddenName);
7941 // this.el.dom.setAttribute('autocomplete', 'off');
7944 var cls = 'x-combo-list';
7945 this.list = this.el.select('ul.dropdown-menu',true).first();
7947 //this.list = new Roo.Layer({
7948 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
7951 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
7952 this.list.setWidth(lw);
7954 this.list.on('mouseover', this.onViewOver, this);
7955 this.list.on('mousemove', this.onViewMove, this);
7957 this.list.on('scroll', this.onViewScroll, this);
7960 this.list.swallowEvent('mousewheel');
7961 this.assetHeight = 0;
7964 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
7965 this.assetHeight += this.header.getHeight();
7968 this.innerList = this.list.createChild({cls:cls+'-inner'});
7969 this.innerList.on('mouseover', this.onViewOver, this);
7970 this.innerList.on('mousemove', this.onViewMove, this);
7971 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
7973 if(this.allowBlank && !this.pageSize && !this.disableClear){
7974 this.footer = this.list.createChild({cls:cls+'-ft'});
7975 this.pageTb = new Roo.Toolbar(this.footer);
7979 this.footer = this.list.createChild({cls:cls+'-ft'});
7980 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
7981 {pageSize: this.pageSize});
7985 if (this.pageTb && this.allowBlank && !this.disableClear) {
7987 this.pageTb.add(new Roo.Toolbar.Fill(), {
7988 cls: 'x-btn-icon x-btn-clear',
7994 _this.onSelect(false, -1);
7999 this.assetHeight += this.footer.getHeight();
8004 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8007 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8008 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8010 //this.view.wrapEl.setDisplayed(false);
8011 this.view.on('click', this.onViewClick, this);
8015 this.store.on('beforeload', this.onBeforeLoad, this);
8016 this.store.on('load', this.onLoad, this);
8017 this.store.on('loadexception', this.onLoadException, this);
8020 this.resizer = new Roo.Resizable(this.list, {
8021 pinned:true, handles:'se'
8023 this.resizer.on('resize', function(r, w, h){
8024 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8026 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8027 this.restrictHeight();
8029 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8033 this.editable = true;
8034 this.setEditable(false);
8039 if (typeof(this.events.add.listeners) != 'undefined') {
8041 this.addicon = this.wrap.createChild(
8042 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8044 this.addicon.on('click', function(e) {
8045 this.fireEvent('add', this);
8048 if (typeof(this.events.edit.listeners) != 'undefined') {
8050 this.editicon = this.wrap.createChild(
8051 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8053 this.editicon.setStyle('margin-left', '40px');
8055 this.editicon.on('click', function(e) {
8057 // we fire even if inothing is selected..
8058 this.fireEvent('edit', this, this.lastData );
8064 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8066 this.inKeyMode = true;
8070 "down" : function(e){
8071 if(!this.isExpanded()){
8072 this.onTriggerClick();
8074 this.inKeyMode = true;
8079 "enter" : function(e){
8084 "esc" : function(e){
8088 "tab" : function(e){
8091 if(this.fireEvent("specialkey", this, e)){
8092 this.onViewClick(false);
8100 doRelay : function(foo, bar, hname){
8101 if(hname == 'down' || this.scope.isExpanded()){
8102 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8111 this.queryDelay = Math.max(this.queryDelay || 10,
8112 this.mode == 'local' ? 10 : 250);
8115 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8118 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8120 if(this.editable !== false){
8121 this.inputEl().on("keyup", this.onKeyUp, this);
8123 if(this.forceSelection){
8124 this.on('blur', this.doForce, this);
8128 this.choices = this.el.select('ul.select2-choices', true).first();
8129 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8133 onDestroy : function(){
8135 this.view.setStore(null);
8136 this.view.el.removeAllListeners();
8137 this.view.el.remove();
8138 this.view.purgeListeners();
8141 this.list.dom.innerHTML = '';
8144 this.store.un('beforeload', this.onBeforeLoad, this);
8145 this.store.un('load', this.onLoad, this);
8146 this.store.un('loadexception', this.onLoadException, this);
8148 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
8152 fireKey : function(e){
8153 if(e.isNavKeyPress() && !this.list.isVisible()){
8154 this.fireEvent("specialkey", this, e);
8159 onResize: function(w, h){
8160 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
8162 // if(typeof w != 'number'){
8163 // // we do not handle it!?!?
8166 // var tw = this.trigger.getWidth();
8167 // // tw += this.addicon ? this.addicon.getWidth() : 0;
8168 // // tw += this.editicon ? this.editicon.getWidth() : 0;
8170 // this.inputEl().setWidth( this.adjustWidth('input', x));
8172 // //this.trigger.setStyle('left', x+'px');
8174 // if(this.list && this.listWidth === undefined){
8175 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
8176 // this.list.setWidth(lw);
8177 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8185 * Allow or prevent the user from directly editing the field text. If false is passed,
8186 * the user will only be able to select from the items defined in the dropdown list. This method
8187 * is the runtime equivalent of setting the 'editable' config option at config time.
8188 * @param {Boolean} value True to allow the user to directly edit the field text
8190 setEditable : function(value){
8191 if(value == this.editable){
8194 this.editable = value;
8196 this.inputEl().dom.setAttribute('readOnly', true);
8197 this.inputEl().on('mousedown', this.onTriggerClick, this);
8198 this.inputEl().addClass('x-combo-noedit');
8200 this.inputEl().dom.setAttribute('readOnly', false);
8201 this.inputEl().un('mousedown', this.onTriggerClick, this);
8202 this.inputEl().removeClass('x-combo-noedit');
8208 onBeforeLoad : function(combo,opts){
8213 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
8215 this.restrictHeight();
8216 this.selectedIndex = -1;
8220 onLoad : function(){
8222 this.hasQuery = false;
8228 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8229 this.loading.hide();
8232 if(this.store.getCount() > 0){
8234 this.restrictHeight();
8235 if(this.lastQuery == this.allQuery){
8237 this.inputEl().dom.select();
8239 if(!this.selectByValue(this.value, true)){
8240 this.select(0, true);
8244 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
8245 this.taTask.delay(this.typeAheadDelay);
8249 this.onEmptyResults();
8255 onLoadException : function()
8257 this.hasQuery = false;
8259 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8260 this.loading.hide();
8264 Roo.log(this.store.reader.jsonData);
8265 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
8267 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
8273 onTypeAhead : function(){
8274 if(this.store.getCount() > 0){
8275 var r = this.store.getAt(0);
8276 var newValue = r.data[this.displayField];
8277 var len = newValue.length;
8278 var selStart = this.getRawValue().length;
8280 if(selStart != len){
8281 this.setRawValue(newValue);
8282 this.selectText(selStart, newValue.length);
8288 onSelect : function(record, index){
8290 if(this.fireEvent('beforeselect', this, record, index) !== false){
8292 this.setFromData(index > -1 ? record.data : false);
8295 this.fireEvent('select', this, record, index);
8300 * Returns the currently selected field value or empty string if no value is set.
8301 * @return {String} value The selected value
8303 getValue : function(){
8306 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
8309 if(this.valueField){
8310 return typeof this.value != 'undefined' ? this.value : '';
8312 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
8317 * Clears any text/value currently set in the field
8319 clearValue : function(){
8320 if(this.hiddenField){
8321 this.hiddenField.dom.value = '';
8324 this.setRawValue('');
8325 this.lastSelectionText = '';
8330 * Sets the specified value into the field. If the value finds a match, the corresponding record text
8331 * will be displayed in the field. If the value does not match the data value of an existing item,
8332 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
8333 * Otherwise the field will be blank (although the value will still be set).
8334 * @param {String} value The value to match
8336 setValue : function(v){
8343 if(this.valueField){
8344 var r = this.findRecord(this.valueField, v);
8346 text = r.data[this.displayField];
8347 }else if(this.valueNotFoundText !== undefined){
8348 text = this.valueNotFoundText;
8351 this.lastSelectionText = text;
8352 if(this.hiddenField){
8353 this.hiddenField.dom.value = v;
8355 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
8359 * @property {Object} the last set data for the element
8364 * Sets the value of the field based on a object which is related to the record format for the store.
8365 * @param {Object} value the value to set as. or false on reset?
8367 setFromData : function(o){
8374 var dv = ''; // display value
8375 var vv = ''; // value value..
8377 if (this.displayField) {
8378 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8380 // this is an error condition!!!
8381 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8384 if(this.valueField){
8385 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
8388 if(this.hiddenField){
8389 this.hiddenField.dom.value = vv;
8391 this.lastSelectionText = dv;
8392 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8396 // no hidden field.. - we store the value in 'value', but still display
8397 // display field!!!!
8398 this.lastSelectionText = dv;
8399 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8406 // overridden so that last data is reset..
8407 this.setValue(this.originalValue);
8408 this.clearInvalid();
8409 this.lastData = false;
8411 this.view.clearSelections();
8415 findRecord : function(prop, value){
8417 if(this.store.getCount() > 0){
8418 this.store.each(function(r){
8419 if(r.data[prop] == value){
8431 // returns hidden if it's set..
8432 if (!this.rendered) {return ''};
8433 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
8437 onViewMove : function(e, t){
8438 this.inKeyMode = false;
8442 onViewOver : function(e, t){
8443 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
8446 var item = this.view.findItemFromChild(t);
8448 var index = this.view.indexOf(item);
8449 this.select(index, false);
8454 onViewClick : function(doFocus)
8456 var index = this.view.getSelectedIndexes()[0];
8457 var r = this.store.getAt(index);
8459 this.onSelect(r, index);
8461 if(doFocus !== false && !this.blockFocus){
8462 this.inputEl().focus();
8467 restrictHeight : function(){
8468 //this.innerList.dom.style.height = '';
8469 //var inner = this.innerList.dom;
8470 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
8471 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
8472 //this.list.beginUpdate();
8473 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
8474 this.list.alignTo(this.inputEl(), this.listAlign);
8475 //this.list.endUpdate();
8479 onEmptyResults : function(){
8484 * Returns true if the dropdown list is expanded, else false.
8486 isExpanded : function(){
8487 return this.list.isVisible();
8491 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
8492 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8493 * @param {String} value The data value of the item to select
8494 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8495 * selected item if it is not currently in view (defaults to true)
8496 * @return {Boolean} True if the value matched an item in the list, else false
8498 selectByValue : function(v, scrollIntoView){
8499 if(v !== undefined && v !== null){
8500 var r = this.findRecord(this.valueField || this.displayField, v);
8502 this.select(this.store.indexOf(r), scrollIntoView);
8510 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
8511 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8512 * @param {Number} index The zero-based index of the list item to select
8513 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8514 * selected item if it is not currently in view (defaults to true)
8516 select : function(index, scrollIntoView){
8517 this.selectedIndex = index;
8518 this.view.select(index);
8519 if(scrollIntoView !== false){
8520 var el = this.view.getNode(index);
8522 //this.innerList.scrollChildIntoView(el, false);
8529 selectNext : function(){
8530 var ct = this.store.getCount();
8532 if(this.selectedIndex == -1){
8534 }else if(this.selectedIndex < ct-1){
8535 this.select(this.selectedIndex+1);
8541 selectPrev : function(){
8542 var ct = this.store.getCount();
8544 if(this.selectedIndex == -1){
8546 }else if(this.selectedIndex != 0){
8547 this.select(this.selectedIndex-1);
8553 onKeyUp : function(e){
8554 if(this.editable !== false && !e.isSpecialKey()){
8555 this.lastKey = e.getKey();
8556 this.dqTask.delay(this.queryDelay);
8561 validateBlur : function(){
8562 return !this.list || !this.list.isVisible();
8566 initQuery : function(){
8567 this.doQuery(this.getRawValue());
8571 doForce : function(){
8572 if(this.el.dom.value.length > 0){
8574 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
8580 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
8581 * query allowing the query action to be canceled if needed.
8582 * @param {String} query The SQL query to execute
8583 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
8584 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
8585 * saved in the current store (defaults to false)
8587 doQuery : function(q, forceAll){
8589 if(q === undefined || q === null){
8598 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
8603 forceAll = qe.forceAll;
8604 if(forceAll === true || (q.length >= this.minChars)){
8606 this.hasQuery = true;
8608 if(this.lastQuery != q || this.alwaysQuery){
8610 if(this.mode == 'local'){
8611 this.selectedIndex = -1;
8613 this.store.clearFilter();
8615 this.store.filter(this.displayField, q);
8619 this.store.baseParams[this.queryParam] = q;
8621 var options = {params : this.getParams(q)};
8625 options.params.start = this.page * this.pageSize;
8628 this.store.load(options);
8632 this.selectedIndex = -1;
8637 this.loadNext = false;
8641 getParams : function(q){
8643 //p[this.queryParam] = q;
8647 p.limit = this.pageSize;
8653 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
8655 collapse : function(){
8656 if(!this.isExpanded()){
8661 Roo.get(document).un('mousedown', this.collapseIf, this);
8662 Roo.get(document).un('mousewheel', this.collapseIf, this);
8663 if (!this.editable) {
8664 Roo.get(document).un('keydown', this.listKeyPress, this);
8666 this.fireEvent('collapse', this);
8670 collapseIf : function(e){
8671 var in_combo = e.within(this.el);
8672 var in_list = e.within(this.list);
8674 if (in_combo || in_list) {
8675 //e.stopPropagation();
8684 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8686 expand : function(){
8688 if(this.isExpanded() || !this.hasFocus){
8692 this.list.alignTo(this.inputEl(), this.listAlign);
8694 Roo.get(document).on('mousedown', this.collapseIf, this);
8695 Roo.get(document).on('mousewheel', this.collapseIf, this);
8696 if (!this.editable) {
8697 Roo.get(document).on('keydown', this.listKeyPress, this);
8700 this.fireEvent('expand', this);
8704 // Implements the default empty TriggerField.onTriggerClick function
8705 onTriggerClick : function()
8707 Roo.log('trigger click');
8714 this.loadNext = false;
8716 if(this.isExpanded()){
8718 if (!this.blockFocus) {
8719 this.inputEl().focus();
8723 this.hasFocus = true;
8724 if(this.triggerAction == 'all') {
8725 this.doQuery(this.allQuery, true);
8727 this.doQuery(this.getRawValue());
8729 if (!this.blockFocus) {
8730 this.inputEl().focus();
8734 listKeyPress : function(e)
8736 //Roo.log('listkeypress');
8737 // scroll to first matching element based on key pres..
8738 if (e.isSpecialKey()) {
8741 var k = String.fromCharCode(e.getKey()).toUpperCase();
8744 var csel = this.view.getSelectedNodes();
8745 var cselitem = false;
8747 var ix = this.view.indexOf(csel[0]);
8748 cselitem = this.store.getAt(ix);
8749 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8755 this.store.each(function(v) {
8757 // start at existing selection.
8758 if (cselitem.id == v.id) {
8764 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
8765 match = this.store.indexOf(v);
8771 if (match === false) {
8772 return true; // no more action?
8775 this.view.select(match);
8776 var sn = Roo.get(this.view.getSelectedNodes()[0])
8777 //sn.scrollIntoView(sn.dom.parentNode, false);
8780 onViewScroll : function(e, t){
8782 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
8786 this.hasQuery = true;
8788 this.loading = this.list.select('.loading', true).first();
8790 if(this.loading === null){
8791 this.list.createChild({
8793 cls: 'loading select2-more-results select2-active',
8794 html: 'Loading more results...'
8797 this.loading = this.list.select('.loading', true).first();
8799 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
8801 this.loading.hide();
8804 this.loading.show();
8809 this.loadNext = true;
8811 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
8816 addItem : function(o)
8818 var dv = ''; // display value
8820 if (this.displayField) {
8821 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8823 // this is an error condition!!!
8824 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8831 var choice = this.choices.createChild({
8833 cls: 'select2-search-choice',
8842 cls: 'select2-search-choice-close',
8847 }, this.searchField);
8849 var close = choice.select('a.select2-search-choice-close', true).first()
8851 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
8858 this.inputEl().dom.value = '';
8862 onRemoveItem : function(e, _self, o)
8864 Roo.log('remove item');
8865 var index = this.item.indexOf(o.data) * 1;
8868 Roo.log('not this item?!');
8872 this.item.splice(index, 1);
8877 this.fireEvent('remove', this);
8881 syncValue : function()
8883 if(!this.item.length){
8890 Roo.each(this.item, function(i){
8891 if(_this.valueField){
8892 value.push(i[_this.valueField]);
8899 this.value = value.join(',');
8901 if(this.hiddenField){
8902 this.hiddenField.dom.value = this.value;
8907 * @cfg {Boolean} grow
8911 * @cfg {Number} growMin
8915 * @cfg {Number} growMax
8925 * Ext JS Library 1.1.1
8926 * Copyright(c) 2006-2007, Ext JS, LLC.
8928 * Originally Released Under LGPL - original licence link has changed is not relivant.
8931 * <script type="text/javascript">
8936 * @extends Roo.util.Observable
8937 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
8938 * This class also supports single and multi selection modes. <br>
8939 * Create a data model bound view:
8941 var store = new Roo.data.Store(...);
8943 var view = new Roo.View({
8945 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
8948 selectedClass: "ydataview-selected",
8952 // listen for node click?
8953 view.on("click", function(vw, index, node, e){
8954 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
8958 dataModel.load("foobar.xml");
8960 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
8962 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
8963 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
8965 * Note: old style constructor is still suported (container, template, config)
8969 * @param {Object} config The config object
8972 Roo.View = function(config, depreciated_tpl, depreciated_config){
8974 if (typeof(depreciated_tpl) == 'undefined') {
8975 // new way.. - universal constructor.
8976 Roo.apply(this, config);
8977 this.el = Roo.get(this.el);
8980 this.el = Roo.get(config);
8981 this.tpl = depreciated_tpl;
8982 Roo.apply(this, depreciated_config);
8984 this.wrapEl = this.el.wrap().wrap();
8985 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
8988 if(typeof(this.tpl) == "string"){
8989 this.tpl = new Roo.Template(this.tpl);
8991 // support xtype ctors..
8992 this.tpl = new Roo.factory(this.tpl, Roo);
9004 * @event beforeclick
9005 * Fires before a click is processed. Returns false to cancel the default action.
9006 * @param {Roo.View} this
9007 * @param {Number} index The index of the target node
9008 * @param {HTMLElement} node The target node
9009 * @param {Roo.EventObject} e The raw event object
9011 "beforeclick" : true,
9014 * Fires when a template node is clicked.
9015 * @param {Roo.View} this
9016 * @param {Number} index The index of the target node
9017 * @param {HTMLElement} node The target node
9018 * @param {Roo.EventObject} e The raw event object
9023 * Fires when a template node is double clicked.
9024 * @param {Roo.View} this
9025 * @param {Number} index The index of the target node
9026 * @param {HTMLElement} node The target node
9027 * @param {Roo.EventObject} e The raw event object
9031 * @event contextmenu
9032 * Fires when a template node is right clicked.
9033 * @param {Roo.View} this
9034 * @param {Number} index The index of the target node
9035 * @param {HTMLElement} node The target node
9036 * @param {Roo.EventObject} e The raw event object
9038 "contextmenu" : true,
9040 * @event selectionchange
9041 * Fires when the selected nodes change.
9042 * @param {Roo.View} this
9043 * @param {Array} selections Array of the selected nodes
9045 "selectionchange" : true,
9048 * @event beforeselect
9049 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9050 * @param {Roo.View} this
9051 * @param {HTMLElement} node The node to be selected
9052 * @param {Array} selections Array of currently selected nodes
9054 "beforeselect" : true,
9056 * @event preparedata
9057 * Fires on every row to render, to allow you to change the data.
9058 * @param {Roo.View} this
9059 * @param {Object} data to be rendered (change this)
9061 "preparedata" : true
9069 "click": this.onClick,
9070 "dblclick": this.onDblClick,
9071 "contextmenu": this.onContextMenu,
9075 this.selections = [];
9077 this.cmp = new Roo.CompositeElementLite([]);
9079 this.store = Roo.factory(this.store, Roo.data);
9080 this.setStore(this.store, true);
9083 if ( this.footer && this.footer.xtype) {
9085 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9087 this.footer.dataSource = this.store
9088 this.footer.container = fctr;
9089 this.footer = Roo.factory(this.footer, Roo);
9090 fctr.insertFirst(this.el);
9092 // this is a bit insane - as the paging toolbar seems to detach the el..
9093 // dom.parentNode.parentNode.parentNode
9094 // they get detached?
9098 Roo.View.superclass.constructor.call(this);
9103 Roo.extend(Roo.View, Roo.util.Observable, {
9106 * @cfg {Roo.data.Store} store Data store to load data from.
9111 * @cfg {String|Roo.Element} el The container element.
9116 * @cfg {String|Roo.Template} tpl The template used by this View
9120 * @cfg {String} dataName the named area of the template to use as the data area
9121 * Works with domtemplates roo-name="name"
9125 * @cfg {String} selectedClass The css class to add to selected nodes
9127 selectedClass : "x-view-selected",
9129 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9134 * @cfg {String} text to display on mask (default Loading)
9138 * @cfg {Boolean} multiSelect Allow multiple selection
9140 multiSelect : false,
9142 * @cfg {Boolean} singleSelect Allow single selection
9144 singleSelect: false,
9147 * @cfg {Boolean} toggleSelect - selecting
9149 toggleSelect : false,
9152 * Returns the element this view is bound to.
9153 * @return {Roo.Element}
9162 * Refreshes the view. - called by datachanged on the store. - do not call directly.
9164 refresh : function(){
9168 // if we are using something like 'domtemplate', then
9169 // the what gets used is:
9170 // t.applySubtemplate(NAME, data, wrapping data..)
9171 // the outer template then get' applied with
9172 // the store 'extra data'
9173 // and the body get's added to the
9174 // roo-name="data" node?
9175 // <span class='roo-tpl-{name}'></span> ?????
9179 this.clearSelections();
9182 var records = this.store.getRange();
9183 if(records.length < 1) {
9185 // is this valid?? = should it render a template??
9187 this.el.update(this.emptyText);
9191 if (this.dataName) {
9192 this.el.update(t.apply(this.store.meta)); //????
9193 el = this.el.child('.roo-tpl-' + this.dataName);
9196 for(var i = 0, len = records.length; i < len; i++){
9197 var data = this.prepareData(records[i].data, i, records[i]);
9198 this.fireEvent("preparedata", this, data, i, records[i]);
9199 html[html.length] = Roo.util.Format.trim(
9201 t.applySubtemplate(this.dataName, data, this.store.meta) :
9208 el.update(html.join(""));
9209 this.nodes = el.dom.childNodes;
9210 this.updateIndexes(0);
9215 * Function to override to reformat the data that is sent to
9216 * the template for each node.
9217 * DEPRICATED - use the preparedata event handler.
9218 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9219 * a JSON object for an UpdateManager bound view).
9221 prepareData : function(data, index, record)
9223 this.fireEvent("preparedata", this, data, index, record);
9227 onUpdate : function(ds, record){
9228 Roo.log('on update');
9229 this.clearSelections();
9230 var index = this.store.indexOf(record);
9231 var n = this.nodes[index];
9232 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
9233 n.parentNode.removeChild(n);
9234 this.updateIndexes(index, index);
9240 onAdd : function(ds, records, index)
9242 Roo.log(['on Add', ds, records, index] );
9243 this.clearSelections();
9244 if(this.nodes.length == 0){
9248 var n = this.nodes[index];
9249 for(var i = 0, len = records.length; i < len; i++){
9250 var d = this.prepareData(records[i].data, i, records[i]);
9252 this.tpl.insertBefore(n, d);
9255 this.tpl.append(this.el, d);
9258 this.updateIndexes(index);
9261 onRemove : function(ds, record, index){
9262 Roo.log('onRemove');
9263 this.clearSelections();
9264 var el = this.dataName ?
9265 this.el.child('.roo-tpl-' + this.dataName) :
9268 el.dom.removeChild(this.nodes[index]);
9269 this.updateIndexes(index);
9273 * Refresh an individual node.
9274 * @param {Number} index
9276 refreshNode : function(index){
9277 this.onUpdate(this.store, this.store.getAt(index));
9280 updateIndexes : function(startIndex, endIndex){
9281 var ns = this.nodes;
9282 startIndex = startIndex || 0;
9283 endIndex = endIndex || ns.length - 1;
9284 for(var i = startIndex; i <= endIndex; i++){
9285 ns[i].nodeIndex = i;
9290 * Changes the data store this view uses and refresh the view.
9291 * @param {Store} store
9293 setStore : function(store, initial){
9294 if(!initial && this.store){
9295 this.store.un("datachanged", this.refresh);
9296 this.store.un("add", this.onAdd);
9297 this.store.un("remove", this.onRemove);
9298 this.store.un("update", this.onUpdate);
9299 this.store.un("clear", this.refresh);
9300 this.store.un("beforeload", this.onBeforeLoad);
9301 this.store.un("load", this.onLoad);
9302 this.store.un("loadexception", this.onLoad);
9306 store.on("datachanged", this.refresh, this);
9307 store.on("add", this.onAdd, this);
9308 store.on("remove", this.onRemove, this);
9309 store.on("update", this.onUpdate, this);
9310 store.on("clear", this.refresh, this);
9311 store.on("beforeload", this.onBeforeLoad, this);
9312 store.on("load", this.onLoad, this);
9313 store.on("loadexception", this.onLoad, this);
9321 * onbeforeLoad - masks the loading area.
9324 onBeforeLoad : function(store,opts)
9326 Roo.log('onBeforeLoad');
9330 this.el.mask(this.mask ? this.mask : "Loading" );
9332 onLoad : function ()
9339 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9340 * @param {HTMLElement} node
9341 * @return {HTMLElement} The template node
9343 findItemFromChild : function(node){
9344 var el = this.dataName ?
9345 this.el.child('.roo-tpl-' + this.dataName,true) :
9348 if(!node || node.parentNode == el){
9351 var p = node.parentNode;
9352 while(p && p != el){
9353 if(p.parentNode == el){
9362 onClick : function(e){
9363 var item = this.findItemFromChild(e.getTarget());
9365 var index = this.indexOf(item);
9366 if(this.onItemClick(item, index, e) !== false){
9367 this.fireEvent("click", this, index, item, e);
9370 this.clearSelections();
9375 onContextMenu : function(e){
9376 var item = this.findItemFromChild(e.getTarget());
9378 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9383 onDblClick : function(e){
9384 var item = this.findItemFromChild(e.getTarget());
9386 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9390 onItemClick : function(item, index, e)
9392 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9395 if (this.toggleSelect) {
9396 var m = this.isSelected(item) ? 'unselect' : 'select';
9399 _t[m](item, true, false);
9402 if(this.multiSelect || this.singleSelect){
9403 if(this.multiSelect && e.shiftKey && this.lastSelection){
9404 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9406 this.select(item, this.multiSelect && e.ctrlKey);
9407 this.lastSelection = item;
9415 * Get the number of selected nodes.
9418 getSelectionCount : function(){
9419 return this.selections.length;
9423 * Get the currently selected nodes.
9424 * @return {Array} An array of HTMLElements
9426 getSelectedNodes : function(){
9427 return this.selections;
9431 * Get the indexes of the selected nodes.
9434 getSelectedIndexes : function(){
9435 var indexes = [], s = this.selections;
9436 for(var i = 0, len = s.length; i < len; i++){
9437 indexes.push(s[i].nodeIndex);
9443 * Clear all selections
9444 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9446 clearSelections : function(suppressEvent){
9447 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9448 this.cmp.elements = this.selections;
9449 this.cmp.removeClass(this.selectedClass);
9450 this.selections = [];
9452 this.fireEvent("selectionchange", this, this.selections);
9458 * Returns true if the passed node is selected
9459 * @param {HTMLElement/Number} node The node or node index
9462 isSelected : function(node){
9463 var s = this.selections;
9467 node = this.getNode(node);
9468 return s.indexOf(node) !== -1;
9473 * @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
9474 * @param {Boolean} keepExisting (optional) true to keep existing selections
9475 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9477 select : function(nodeInfo, keepExisting, suppressEvent){
9478 if(nodeInfo instanceof Array){
9480 this.clearSelections(true);
9482 for(var i = 0, len = nodeInfo.length; i < len; i++){
9483 this.select(nodeInfo[i], true, true);
9487 var node = this.getNode(nodeInfo);
9488 if(!node || this.isSelected(node)){
9489 return; // already selected.
9492 this.clearSelections(true);
9494 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9495 Roo.fly(node).addClass(this.selectedClass);
9496 this.selections.push(node);
9498 this.fireEvent("selectionchange", this, this.selections);
9506 * @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
9507 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
9508 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9510 unselect : function(nodeInfo, keepExisting, suppressEvent)
9512 if(nodeInfo instanceof Array){
9513 Roo.each(this.selections, function(s) {
9514 this.unselect(s, nodeInfo);
9518 var node = this.getNode(nodeInfo);
9519 if(!node || !this.isSelected(node)){
9520 Roo.log("not selected");
9521 return; // not selected.
9525 Roo.each(this.selections, function(s) {
9527 Roo.fly(node).removeClass(this.selectedClass);
9534 this.selections= ns;
9535 this.fireEvent("selectionchange", this, this.selections);
9539 * Gets a template node.
9540 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9541 * @return {HTMLElement} The node or null if it wasn't found
9543 getNode : function(nodeInfo){
9544 if(typeof nodeInfo == "string"){
9545 return document.getElementById(nodeInfo);
9546 }else if(typeof nodeInfo == "number"){
9547 return this.nodes[nodeInfo];
9553 * Gets a range template nodes.
9554 * @param {Number} startIndex
9555 * @param {Number} endIndex
9556 * @return {Array} An array of nodes
9558 getNodes : function(start, end){
9559 var ns = this.nodes;
9561 end = typeof end == "undefined" ? ns.length - 1 : end;
9564 for(var i = start; i <= end; i++){
9568 for(var i = start; i >= end; i--){
9576 * Finds the index of the passed node
9577 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9578 * @return {Number} The index of the node or -1
9580 indexOf : function(node){
9581 node = this.getNode(node);
9582 if(typeof node.nodeIndex == "number"){
9583 return node.nodeIndex;
9585 var ns = this.nodes;
9586 for(var i = 0, len = ns.length; i < len; i++){
9597 * based on jquery fullcalendar
9601 Roo.bootstrap = Roo.bootstrap || {};
9603 * @class Roo.bootstrap.Calendar
9604 * @extends Roo.bootstrap.Component
9605 * Bootstrap Calendar class
9606 * @cfg {Boolean} loadMask (true|false) default false
9609 * Create a new Container
9610 * @param {Object} config The config object
9615 Roo.bootstrap.Calendar = function(config){
9616 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
9620 * Fires when a date is selected
9621 * @param {DatePicker} this
9622 * @param {Date} date The selected date
9626 * @event monthchange
9627 * Fires when the displayed month changes
9628 * @param {DatePicker} this
9629 * @param {Date} date The selected month
9631 'monthchange': true,
9634 * Fires when mouse over an event
9635 * @param {Calendar} this
9636 * @param {event} Event
9641 * Fires when the mouse leaves an
9642 * @param {Calendar} this
9648 * Fires when the mouse click an
9649 * @param {Calendar} this
9658 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
9661 * @cfg {Number} startDay
9662 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
9668 getAutoCreate : function(){
9671 var fc_button = function(name, corner, style, content ) {
9672 return Roo.apply({},{
9674 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
9676 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
9679 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
9687 style : 'width:100%',
9694 cls : 'fc-header-left',
9696 fc_button('prev', 'left', 'arrow', '‹' ),
9697 fc_button('next', 'right', 'arrow', '›' ),
9698 { tag: 'span', cls: 'fc-header-space' },
9699 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
9707 cls : 'fc-header-center',
9711 cls: 'fc-header-title',
9714 html : 'month / year'
9722 cls : 'fc-header-right',
9724 /* fc_button('month', 'left', '', 'month' ),
9725 fc_button('week', '', '', 'week' ),
9726 fc_button('day', 'right', '', 'day' )
9738 var cal_heads = function() {
9740 // fixme - handle this.
9742 for (var i =0; i < Date.dayNames.length; i++) {
9743 var d = Date.dayNames[i];
9746 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
9747 html : d.substring(0,3)
9751 ret[0].cls += ' fc-first';
9752 ret[6].cls += ' fc-last';
9755 var cal_cell = function(n) {
9758 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
9763 cls: 'fc-day-number',
9767 cls: 'fc-day-content',
9771 style: 'position: relative;' // height: 17px;
9783 var cal_rows = function() {
9786 for (var r = 0; r < 6; r++) {
9793 for (var i =0; i < Date.dayNames.length; i++) {
9794 var d = Date.dayNames[i];
9795 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
9798 row.cn[0].cls+=' fc-first';
9799 row.cn[0].cn[0].style = 'min-height:90px';
9800 row.cn[6].cls+=' fc-last';
9804 ret[0].cls += ' fc-first';
9805 ret[4].cls += ' fc-prev-last';
9806 ret[5].cls += ' fc-last';
9813 cls: 'fc-border-separate',
9814 style : 'width:100%',
9822 cls : 'fc-first fc-last',
9841 style : "position: relative;",
9844 cls : 'fc-view fc-view-month fc-grid',
9845 style : 'position: relative',
9846 unselectable : 'on',
9849 cls : 'fc-event-container',
9850 style : 'position:absolute;z-index:8;top:0;left:0;'
9868 initEvents : function()
9871 throw "can not find store for calendar";
9877 style: "text-align:center",
9881 style: "background-color:white;width:50%;margin:250 auto",
9885 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
9896 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
9898 var size = this.el.select('.fc-content', true).first().getSize();
9899 this.maskEl.setSize(size.width, size.height);
9900 this.maskEl.enableDisplayMode("block");
9905 this.store = Roo.factory(this.store, Roo.data);
9906 this.store.on('load', this.onLoad, this);
9907 this.store.on('beforeload', this.onBeforeLoad, this);
9911 this.cells = this.el.select('.fc-day',true);
9912 //Roo.log(this.cells);
9913 this.textNodes = this.el.query('.fc-day-number');
9914 this.cells.addClassOnOver('fc-state-hover');
9916 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
9917 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
9918 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
9919 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
9921 this.on('monthchange', this.onMonthChange, this);
9923 this.update(new Date().clearTime());
9926 resize : function() {
9927 var sz = this.el.getSize();
9929 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
9930 this.el.select('.fc-day-content div',true).setHeight(34);
9935 showPrevMonth : function(e){
9936 this.update(this.activeDate.add("mo", -1));
9938 showToday : function(e){
9939 this.update(new Date().clearTime());
9942 showNextMonth : function(e){
9943 this.update(this.activeDate.add("mo", 1));
9947 showPrevYear : function(){
9948 this.update(this.activeDate.add("y", -1));
9952 showNextYear : function(){
9953 this.update(this.activeDate.add("y", 1));
9958 update : function(date)
9960 var vd = this.activeDate;
9961 this.activeDate = date;
9962 // if(vd && this.el){
9963 // var t = date.getTime();
9964 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
9965 // Roo.log('using add remove');
9967 // this.fireEvent('monthchange', this, date);
9969 // this.cells.removeClass("fc-state-highlight");
9970 // this.cells.each(function(c){
9971 // if(c.dateValue == t){
9972 // c.addClass("fc-state-highlight");
9973 // setTimeout(function(){
9974 // try{c.dom.firstChild.focus();}catch(e){}
9984 var days = date.getDaysInMonth();
9986 var firstOfMonth = date.getFirstDateOfMonth();
9987 var startingPos = firstOfMonth.getDay()-this.startDay;
9989 if(startingPos < this.startDay){
9993 var pm = date.add(Date.MONTH, -1);
9994 var prevStart = pm.getDaysInMonth()-startingPos;
9996 this.cells = this.el.select('.fc-day',true);
9997 this.textNodes = this.el.query('.fc-day-number');
9998 this.cells.addClassOnOver('fc-state-hover');
10000 var cells = this.cells.elements;
10001 var textEls = this.textNodes;
10003 Roo.each(cells, function(cell){
10004 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10007 days += startingPos;
10009 // convert everything to numbers so it's fast
10010 var day = 86400000;
10011 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10014 //Roo.log(prevStart);
10016 var today = new Date().clearTime().getTime();
10017 var sel = date.clearTime().getTime();
10018 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10019 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10020 var ddMatch = this.disabledDatesRE;
10021 var ddText = this.disabledDatesText;
10022 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10023 var ddaysText = this.disabledDaysText;
10024 var format = this.format;
10026 var setCellClass = function(cal, cell){
10028 //Roo.log('set Cell Class');
10030 var t = d.getTime();
10034 cell.dateValue = t;
10036 cell.className += " fc-today";
10037 cell.className += " fc-state-highlight";
10038 cell.title = cal.todayText;
10041 // disable highlight in other month..
10042 //cell.className += " fc-state-highlight";
10047 cell.className = " fc-state-disabled";
10048 cell.title = cal.minText;
10052 cell.className = " fc-state-disabled";
10053 cell.title = cal.maxText;
10057 if(ddays.indexOf(d.getDay()) != -1){
10058 cell.title = ddaysText;
10059 cell.className = " fc-state-disabled";
10062 if(ddMatch && format){
10063 var fvalue = d.dateFormat(format);
10064 if(ddMatch.test(fvalue)){
10065 cell.title = ddText.replace("%0", fvalue);
10066 cell.className = " fc-state-disabled";
10070 if (!cell.initialClassName) {
10071 cell.initialClassName = cell.dom.className;
10074 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10079 for(; i < startingPos; i++) {
10080 textEls[i].innerHTML = (++prevStart);
10081 d.setDate(d.getDate()+1);
10083 cells[i].className = "fc-past fc-other-month";
10084 setCellClass(this, cells[i]);
10089 for(; i < days; i++){
10090 intDay = i - startingPos + 1;
10091 textEls[i].innerHTML = (intDay);
10092 d.setDate(d.getDate()+1);
10094 cells[i].className = ''; // "x-date-active";
10095 setCellClass(this, cells[i]);
10099 for(; i < 42; i++) {
10100 textEls[i].innerHTML = (++extraDays);
10101 d.setDate(d.getDate()+1);
10103 cells[i].className = "fc-future fc-other-month";
10104 setCellClass(this, cells[i]);
10107 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10109 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10111 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10112 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10114 if(totalRows != 6){
10115 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10116 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10119 this.fireEvent('monthchange', this, date);
10123 if(!this.internalRender){
10124 var main = this.el.dom.firstChild;
10125 var w = main.offsetWidth;
10126 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10127 Roo.fly(main).setWidth(w);
10128 this.internalRender = true;
10129 // opera does not respect the auto grow header center column
10130 // then, after it gets a width opera refuses to recalculate
10131 // without a second pass
10132 if(Roo.isOpera && !this.secondPass){
10133 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10134 this.secondPass = true;
10135 this.update.defer(10, this, [date]);
10142 findCell : function(dt) {
10143 dt = dt.clearTime().getTime();
10145 this.cells.each(function(c){
10146 //Roo.log("check " +c.dateValue + '?=' + dt);
10147 if(c.dateValue == dt){
10157 findCells : function(ev) {
10158 var s = ev.start.clone().clearTime().getTime();
10160 var e= ev.end.clone().clearTime().getTime();
10163 this.cells.each(function(c){
10164 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
10166 if(c.dateValue > e){
10169 if(c.dateValue < s){
10178 findBestRow: function(cells)
10182 for (var i =0 ; i < cells.length;i++) {
10183 ret = Math.max(cells[i].rows || 0,ret);
10190 addItem : function(ev)
10192 // look for vertical location slot in
10193 var cells = this.findCells(ev);
10195 ev.row = this.findBestRow(cells);
10197 // work out the location.
10201 for(var i =0; i < cells.length; i++) {
10209 if (crow.start.getY() == cells[i].getY()) {
10211 crow.end = cells[i];
10227 for (var i = 0; i < cells.length;i++) {
10228 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
10232 this.calevents.push(ev);
10235 clearEvents: function() {
10237 if(!this.calevents){
10241 Roo.each(this.cells.elements, function(c){
10245 Roo.each(this.calevents, function(e) {
10246 Roo.each(e.els, function(el) {
10247 el.un('mouseenter' ,this.onEventEnter, this);
10248 el.un('mouseleave' ,this.onEventLeave, this);
10255 renderEvents: function()
10257 // first make sure there is enough space..
10259 this.cells.each(function(c) {
10261 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
10264 for (var e = 0; e < this.calevents.length; e++) {
10265 var ev = this.calevents[e];
10266 var cells = ev.cells;
10267 var rows = ev.rows;
10269 for(var i =0; i < rows.length; i++) {
10272 // how many rows should it span..
10275 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
10276 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
10278 unselectable : "on",
10281 cls: 'fc-event-inner',
10285 cls: 'fc-event-time',
10286 html : cells.length > 1 ? '' : ev.time
10290 cls: 'fc-event-title',
10291 html : String.format('{0}', ev.title)
10298 cls: 'ui-resizable-handle ui-resizable-e',
10299 html : '  '
10305 cfg.cls += ' fc-event-start';
10307 if ((i+1) == rows.length) {
10308 cfg.cls += ' fc-event-end';
10311 var ctr = this.el.select('.fc-event-container',true).first();
10312 var cg = ctr.createChild(cfg);
10314 cg.on('mouseenter' ,this.onEventEnter, this, ev);
10315 cg.on('mouseleave' ,this.onEventLeave, this, ev);
10316 cg.on('click', this.onEventClick, this, ev);
10320 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
10321 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
10323 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
10324 cg.setWidth(ebox.right - sbox.x -2);
10332 onEventEnter: function (e, el,event,d) {
10333 this.fireEvent('evententer', this, el, event);
10336 onEventLeave: function (e, el,event,d) {
10337 this.fireEvent('eventleave', this, el, event);
10340 onEventClick: function (e, el,event,d) {
10341 this.fireEvent('eventclick', this, el, event);
10344 onMonthChange: function () {
10348 onLoad: function ()
10350 this.calevents = [];
10353 if(this.store.getCount() > 0){
10354 this.store.data.each(function(d){
10357 start: new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s'),
10358 end : new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s'),
10359 time : d.data.start_time,
10360 title : d.data.title,
10361 description : d.data.description,
10362 venue : d.data.venue
10367 this.renderEvents();
10370 this.maskEl.hide();
10374 onBeforeLoad: function()
10376 this.clearEvents();
10379 this.maskEl.show();
10393 * @class Roo.bootstrap.Popover
10394 * @extends Roo.bootstrap.Component
10395 * Bootstrap Popover class
10396 * @cfg {String} html contents of the popover (or false to use children..)
10397 * @cfg {String} title of popover (or false to hide)
10398 * @cfg {String} placement how it is placed
10399 * @cfg {String} trigger click || hover (or false to trigger manually)
10400 * @cfg {String} over what (parent or false to trigger manually.)
10403 * Create a new Popover
10404 * @param {Object} config The config object
10407 Roo.bootstrap.Popover = function(config){
10408 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
10411 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
10413 title: 'Fill in a title',
10416 placement : 'right',
10417 trigger : 'hover', // hover
10421 can_build_overlaid : false,
10423 getChildContainer : function()
10425 return this.el.select('.popover-content',true).first();
10428 getAutoCreate : function(){
10429 Roo.log('make popover?');
10431 cls : 'popover roo-dynamic',
10432 style: 'display:block',
10438 cls : 'popover-inner',
10442 cls: 'popover-title',
10446 cls : 'popover-content',
10457 setTitle: function(str)
10459 this.el.select('.popover-title',true).first().dom.innerHTML = str;
10461 setContent: function(str)
10463 this.el.select('.popover-content',true).first().dom.innerHTML = str;
10465 // as it get's added to the bottom of the page.
10466 onRender : function(ct, position)
10468 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
10470 var cfg = Roo.apply({}, this.getAutoCreate());
10474 cfg.cls += ' ' + this.cls;
10477 cfg.style = this.style;
10479 Roo.log("adding to ")
10480 this.el = Roo.get(document.body).createChild(cfg, position);
10486 initEvents : function()
10488 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
10489 this.el.enableDisplayMode('block');
10491 if (this.over === false) {
10494 if (this.triggers === false) {
10497 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10498 var triggers = this.trigger ? this.trigger.split(' ') : [];
10499 Roo.each(triggers, function(trigger) {
10501 if (trigger == 'click') {
10502 on_el.on('click', this.toggle, this);
10503 } else if (trigger != 'manual') {
10504 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
10505 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
10507 on_el.on(eventIn ,this.enter, this);
10508 on_el.on(eventOut, this.leave, this);
10519 toggle : function () {
10520 this.hoverState == 'in' ? this.leave() : this.enter();
10523 enter : function () {
10526 clearTimeout(this.timeout);
10528 this.hoverState = 'in'
10530 if (!this.delay || !this.delay.show) {
10535 this.timeout = setTimeout(function () {
10536 if (_t.hoverState == 'in') {
10539 }, this.delay.show)
10541 leave : function() {
10542 clearTimeout(this.timeout);
10544 this.hoverState = 'out'
10546 if (!this.delay || !this.delay.hide) {
10551 this.timeout = setTimeout(function () {
10552 if (_t.hoverState == 'out') {
10555 }, this.delay.hide)
10558 show : function (on_el)
10561 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10564 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
10565 if (this.html !== false) {
10566 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
10568 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
10569 if (!this.title.length) {
10570 this.el.select('.popover-title',true).hide();
10573 var placement = typeof this.placement == 'function' ?
10574 this.placement.call(this, this.el, on_el) :
10577 var autoToken = /\s?auto?\s?/i;
10578 var autoPlace = autoToken.test(placement);
10580 placement = placement.replace(autoToken, '') || 'top';
10584 //this.el.setXY([0,0]);
10586 this.el.dom.style.display='block';
10587 this.el.addClass(placement);
10589 //this.el.appendTo(on_el);
10591 var p = this.getPosition();
10592 var box = this.el.getBox();
10597 var align = Roo.bootstrap.Popover.alignment[placement]
10598 this.el.alignTo(on_el, align[0],align[1]);
10599 //var arrow = this.el.select('.arrow',true).first();
10600 //arrow.set(align[2],
10602 this.el.addClass('in');
10603 this.hoverState = null;
10605 if (this.el.hasClass('fade')) {
10612 this.el.setXY([0,0]);
10613 this.el.removeClass('in');
10620 Roo.bootstrap.Popover.alignment = {
10621 'left' : ['r-l', [-10,0], 'right'],
10622 'right' : ['l-r', [10,0], 'left'],
10623 'bottom' : ['t-b', [0,10], 'top'],
10624 'top' : [ 'b-t', [0,-10], 'bottom']
10635 * @class Roo.bootstrap.Progress
10636 * @extends Roo.bootstrap.Component
10637 * Bootstrap Progress class
10638 * @cfg {Boolean} striped striped of the progress bar
10639 * @cfg {Boolean} active animated of the progress bar
10643 * Create a new Progress
10644 * @param {Object} config The config object
10647 Roo.bootstrap.Progress = function(config){
10648 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
10651 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
10656 getAutoCreate : function(){
10664 cfg.cls += ' progress-striped';
10668 cfg.cls += ' active';
10687 * @class Roo.bootstrap.ProgressBar
10688 * @extends Roo.bootstrap.Component
10689 * Bootstrap ProgressBar class
10690 * @cfg {Number} aria_valuenow aria-value now
10691 * @cfg {Number} aria_valuemin aria-value min
10692 * @cfg {Number} aria_valuemax aria-value max
10693 * @cfg {String} label label for the progress bar
10694 * @cfg {String} panel (success | info | warning | danger )
10695 * @cfg {String} role role of the progress bar
10696 * @cfg {String} sr_only text
10700 * Create a new ProgressBar
10701 * @param {Object} config The config object
10704 Roo.bootstrap.ProgressBar = function(config){
10705 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
10708 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
10712 aria_valuemax : 100,
10718 getAutoCreate : function()
10723 cls: 'progress-bar',
10724 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
10736 cfg.role = this.role;
10739 if(this.aria_valuenow){
10740 cfg['aria-valuenow'] = this.aria_valuenow;
10743 if(this.aria_valuemin){
10744 cfg['aria-valuemin'] = this.aria_valuemin;
10747 if(this.aria_valuemax){
10748 cfg['aria-valuemax'] = this.aria_valuemax;
10751 if(this.label && !this.sr_only){
10752 cfg.html = this.label;
10756 cfg.cls += ' progress-bar-' + this.panel;
10762 update : function(aria_valuenow)
10764 this.aria_valuenow = aria_valuenow;
10766 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
10781 * @class Roo.bootstrap.TabPanel
10782 * @extends Roo.bootstrap.Component
10783 * Bootstrap TabPanel class
10784 * @cfg {Boolean} active panel active
10785 * @cfg {String} html panel content
10786 * @cfg {String} tabId tab relate id
10790 * Create a new TabPanel
10791 * @param {Object} config The config object
10794 Roo.bootstrap.TabPanel = function(config){
10795 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
10798 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
10804 getAutoCreate : function(){
10808 html: this.html || ''
10812 cfg.cls += ' active';
10816 cfg.tabId = this.tabId;
10834 * @class Roo.bootstrap.DateField
10835 * @extends Roo.bootstrap.Input
10836 * Bootstrap DateField class
10837 * @cfg {Number} weekStart default 0
10838 * @cfg {Number} weekStart default 0
10839 * @cfg {Number} viewMode default empty, (months|years)
10840 * @cfg {Number} minViewMode default empty, (months|years)
10841 * @cfg {Number} startDate default -Infinity
10842 * @cfg {Number} endDate default Infinity
10843 * @cfg {Boolean} todayHighlight default false
10844 * @cfg {Boolean} todayBtn default false
10845 * @cfg {Boolean} calendarWeeks default false
10846 * @cfg {Object} daysOfWeekDisabled default empty
10847 * @cfg {Boolean} showTime pick the time (default true)
10849 * @cfg {Boolean} keyboardNavigation default true
10850 * @cfg {String} language default en
10853 * Create a new DateField
10854 * @param {Object} config The config object
10857 Roo.bootstrap.DateField = function(config){
10858 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
10861 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
10864 * @cfg {String} format
10865 * The default date format string which can be overriden for localization support. The format must be
10866 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10870 * @cfg {String} altFormats
10871 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
10872 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
10874 // altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
10875 altFormats : false,
10883 todayHighlight : false,
10889 keyboardNavigation: true,
10891 calendarWeeks: false,
10893 startDate: -Infinity,
10897 daysOfWeekDisabled: [],
10901 UTCDate: function()
10903 return new Date(Date.UTC.apply(Date, arguments));
10906 UTCTime: function()
10908 return new Date(Date.UTC.apply(Date, arguments));
10911 UTCToday: function()
10913 var today = new Date();
10914 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
10917 UTCTodayTime: function()
10919 var today = new Date();
10920 return this.UTCTime(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), today.getUTCHours(), today.getUTCMinutes());
10923 getDate: function() {
10924 var d = this.getUTCDate();
10925 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
10928 getUTCDate: function() {
10932 setDate: function(d) {
10933 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
10936 setUTCDate: function(d) {
10938 this.setValue(this.formatDate(this.date));
10941 onRender: function(ct, position)
10944 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
10946 this.language = this.language || 'en';
10947 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
10948 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
10950 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
10951 this.format = this.format || 'm/d/y';
10952 this.isInline = false;
10953 this.isInput = true;
10954 this.component = this.el.select('.add-on', true).first() || false;
10955 this.component = (this.component && this.component.length === 0) ? false : this.component;
10956 this.hasInput = this.component && this.inputEL().length;
10958 if (typeof(this.minViewMode === 'string')) {
10959 switch (this.minViewMode) {
10961 this.minViewMode = 2;
10964 this.minViewMode = 3;
10967 this.minViewMode = 1;
10970 this.minViewMode = 0;
10975 if (typeof(this.viewMode === 'string')) {
10976 switch (this.viewMode) {
10992 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
10994 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
10996 this.picker().on('mousedown', this.onMousedown, this);
10997 this.picker().on('click', this.onClick, this);
10999 this.picker().addClass('datepicker-dropdown');
11001 this.startViewMode = this.viewMode;
11003 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11005 this.setStartDate(this.startDate);
11006 this.setEndDate(this.endDate);
11008 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11018 var dayFoot = this.picker().select('>.datepicker-days tfoot th', true).first();
11019 var timeFoot = this.picker().select('>.datepicker-time tfoot th', true).first();
11021 var dayFootIcon = this.picker().select('>.datepicker-days tfoot span.picker-switch-icon', true).first();
11022 var timeFootIcon = this.picker().select('>.datepicker-time tfoot span.picker-switch-icon', true).first();
11024 timeFoot.addClass('switch-calendar');
11025 dayFoot.addClass('switch-time');
11027 timeFootIcon.addClass('switch-calendar');
11028 timeFootIcon.addClass('glyphicon-calendar');
11030 dayFootIcon.addClass('switch-time');
11031 dayFootIcon.addClass('glyphicon-time');
11033 var hours_up = this.picker().select('>.datepicker-time span.hours-up', true).first();
11034 var hours_down = this.picker().select('>.datepicker-time span.hours-down', true).first();
11035 var minutes_up = this.picker().select('>.datepicker-time span.minutes-up', true).first();
11036 var minutes_down = this.picker().select('>.datepicker-time span.minutes-down', true).first();
11038 var period = this.picker().select('>.datepicker-time button.period-btn', true).first();
11040 hours_up.on('click', this.onIncrementHours, this);
11041 hours_down.on('click', this.onDecrementHours, this);
11042 minutes_up.on('click', this.onIncrementMinutes, this);
11043 minutes_down.on('click', this.onDecrementMinutes, this);
11045 period.on('click', this.onTogglePeriod, this);
11050 Roo.each(this.picker().select('tfoot th', true).elements, function(v){
11055 if(this.isInline) {
11060 picker : function()
11062 return this.el.select('.datepicker', true).first();
11065 fillDow: function()
11067 var dowCnt = this.weekStart;
11076 if(this.calendarWeeks){
11084 while (dowCnt < this.weekStart + 7) {
11088 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11092 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11095 fillMonths: function()
11098 var months = this.picker().select('>.datepicker-months td', true).first();
11100 months.dom.innerHTML = '';
11106 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
11109 months.createChild(month);
11114 fillTime: function()
11116 var time = this.picker().select('>.datepicker-time tbody', true).first();
11118 time.dom.innerHTML = '';
11133 cls: 'hours-up glyphicon glyphicon-chevron-up'
11153 cls: 'minutes-up glyphicon glyphicon-chevron-up'
11174 cls: 'timepicker-hour',
11189 cls: 'timepicker-minute',
11204 cls: 'btn btn-primary period-btn',
11226 cls: 'hours-down glyphicon glyphicon-chevron-down'
11246 cls: 'minutes-down glyphicon glyphicon-chevron-down'
11261 update: function(){
11263 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
11265 if (this.date < this.startDate) {
11266 this.viewDate = new Date(this.startDate);
11267 } else if (this.date > this.endDate) {
11268 this.viewDate = new Date(this.endDate);
11270 this.viewDate = new Date(this.date);
11277 var d = new Date(this.viewDate),
11278 year = d.getUTCFullYear(),
11279 month = d.getUTCMonth(),
11280 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
11281 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
11282 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
11283 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
11284 currentDate = this.date && this.date.valueOf(),
11285 today = this.UTCToday();
11287 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
11289 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
11291 // this.picker.select('>tfoot th.today').
11292 // .text(dates[this.language].today)
11293 // .toggle(this.todayBtn !== false);
11295 this.updateNavArrows();
11298 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
11300 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
11302 prevMonth.setUTCDate(day);
11304 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
11306 var nextMonth = new Date(prevMonth);
11308 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
11310 nextMonth = nextMonth.valueOf();
11312 var fillMonths = false;
11314 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
11316 while(prevMonth.valueOf() < nextMonth) {
11319 if (prevMonth.getUTCDay() === this.weekStart) {
11321 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
11329 if(this.calendarWeeks){
11330 // ISO 8601: First week contains first thursday.
11331 // ISO also states week starts on Monday, but we can be more abstract here.
11333 // Start of current week: based on weekstart/current date
11334 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
11335 // Thursday of this week
11336 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
11337 // First Thursday of year, year from thursday
11338 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
11339 // Calendar week: ms between thursdays, div ms per day, div 7 days
11340 calWeek = (th - yth) / 864e5 / 7 + 1;
11342 fillMonths.cn.push({
11350 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
11352 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
11355 if (this.todayHighlight &&
11356 prevMonth.getUTCFullYear() == today.getFullYear() &&
11357 prevMonth.getUTCMonth() == today.getMonth() &&
11358 prevMonth.getUTCDate() == today.getDate()) {
11359 clsName += ' today';
11362 if (currentDate && prevMonth.valueOf() === currentDate) {
11363 clsName += ' active';
11366 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
11367 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
11368 clsName += ' disabled';
11371 fillMonths.cn.push({
11373 cls: 'day ' + clsName,
11374 html: prevMonth.getDate()
11377 prevMonth.setDate(prevMonth.getDate()+1);
11380 var currentYear = this.date && this.date.getUTCFullYear();
11381 var currentMonth = this.date && this.date.getUTCMonth();
11383 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
11385 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
11386 v.removeClass('active');
11388 if(currentYear === year && k === currentMonth){
11389 v.addClass('active');
11392 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
11393 v.addClass('disabled');
11399 year = parseInt(year/10, 10) * 10;
11401 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
11403 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
11406 for (var i = -1; i < 11; i++) {
11407 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
11409 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
11418 updateTime: function()
11420 this.time = (typeof(this.time) === 'undefined') ? this.UTCTodayTime() : this.time;
11422 var hours = this.time.getHours();
11423 var minutes = this.time.getMinutes();
11425 if(hours * 1 > 12){
11430 hours = '0' + hours;
11434 minutes = '0' + minutes;
11437 var period = this.time.format('A');
11439 this.picker().select('>.datepicker-time span.timepicker-hour', true).first().dom.innerHTML = hours;
11441 this.picker().select('>.datepicker-time span.timepicker-minute', true).first().dom.innerHTML = minutes;
11443 this.picker().select('>.datepicker-time button.period-btn', true).first().dom.innerHTML = period;
11446 showMode: function(dir) {
11448 this.viewMode = Math.max(this.minViewMode, Math.min(3, this.viewMode + dir));
11451 Roo.each(this.picker().select('>div',true).elements, function(v){
11452 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11455 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
11461 if(this.isInline) return;
11463 this.picker().removeClass(['bottom', 'top']);
11465 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
11467 * place to the top of element!
11471 this.picker().addClass('top');
11472 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11477 this.picker().addClass('bottom');
11479 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11482 parseDate : function(value){
11483 if(!value || value instanceof Date){
11486 var v = Date.parseDate(value, this.format);
11487 if (!v && this.useIso) {
11488 v = Date.parseDate(value, 'Y-m-d');
11490 if(!v && this.altFormats){
11491 if(!this.altFormatsArray){
11492 this.altFormatsArray = this.altFormats.split("|");
11494 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
11495 v = Date.parseDate(value, this.altFormatsArray[i]);
11501 formatDate : function(date, fmt){
11502 return (!date || !(date instanceof Date)) ?
11503 date : date.dateFormat(fmt || this.format);
11506 onFocus : function()
11508 Roo.bootstrap.DateField.superclass.onFocus.call(this);
11512 onBlur : function()
11514 Roo.bootstrap.DateField.superclass.onBlur.call(this);
11520 this.picker().show();
11527 if(this.isInline) return;
11528 this.picker().hide();
11529 this.viewMode = this.startViewMode;
11534 onMousedown: function(e){
11535 e.stopPropagation();
11536 e.preventDefault();
11539 keyup: function(e){
11540 Roo.bootstrap.DateField.superclass.keyup.call(this);
11545 fireKey: function(e){
11546 if (!this.picker().isVisible()){
11547 if (e.keyCode == 27) // allow escape to hide and re-show picker
11551 var dateChanged = false,
11553 newDate, newViewDate;
11557 e.preventDefault();
11561 if (!this.keyboardNavigation) break;
11562 dir = e.keyCode == 37 ? -1 : 1;
11565 newDate = this.moveYear(this.date, dir);
11566 newViewDate = this.moveYear(this.viewDate, dir);
11567 } else if (e.shiftKey){
11568 newDate = this.moveMonth(this.date, dir);
11569 newViewDate = this.moveMonth(this.viewDate, dir);
11571 newDate = new Date(this.date);
11572 newDate.setUTCDate(this.date.getUTCDate() + dir);
11573 newViewDate = new Date(this.viewDate);
11574 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
11576 if (this.dateWithinRange(newDate)){
11577 this.date = newDate;
11578 this.viewDate = newViewDate;
11579 this.setValue(this.formatDate(this.date));
11581 e.preventDefault();
11582 dateChanged = true;
11587 if (!this.keyboardNavigation) break;
11588 dir = e.keyCode == 38 ? -1 : 1;
11590 newDate = this.moveYear(this.date, dir);
11591 newViewDate = this.moveYear(this.viewDate, dir);
11592 } else if (e.shiftKey){
11593 newDate = this.moveMonth(this.date, dir);
11594 newViewDate = this.moveMonth(this.viewDate, dir);
11596 newDate = new Date(this.date);
11597 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
11598 newViewDate = new Date(this.viewDate);
11599 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
11601 if (this.dateWithinRange(newDate)){
11602 this.date = newDate;
11603 this.viewDate = newViewDate;
11604 this.setValue(this.formatDate(this.date));
11606 e.preventDefault();
11607 dateChanged = true;
11611 this.setValue(this.formatDate(this.date));
11613 e.preventDefault();
11616 this.setValue(this.formatDate(this.date));
11623 onClick: function(e) {
11624 e.stopPropagation();
11625 e.preventDefault();
11627 var target = e.getTarget();
11629 if(target.nodeName.toLowerCase() === 'i'){
11630 target = Roo.get(target).dom.parentNode;
11633 var nodeName = target.nodeName.trim();
11634 var className = target.className.trim();
11635 var html = target.innerHTML;
11637 switch(nodeName.toLowerCase()) {
11639 switch(className) {
11645 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
11646 switch(this.viewMode){
11648 this.viewDate = this.moveMonth(this.viewDate, dir);
11652 this.viewDate = this.moveYear(this.viewDate, dir);
11658 var date = new Date();
11659 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
11661 this.setValue(this.formatDate(this.date));
11664 case 'switch-time':
11668 case 'switch-calendar':
11675 if (className.indexOf('disabled') === -1) {
11676 this.viewDate.setUTCDate(1);
11677 if (className.indexOf('month') !== -1) {
11678 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
11679 } else if(className.indexOf('picker-switch-icon') !== -1){
11680 if(className.indexOf('switch-time') !== -1){
11691 var year = parseInt(html, 10) || 0;
11692 this.viewDate.setUTCFullYear(year);
11701 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
11702 var day = parseInt(html, 10) || 1;
11703 var year = this.viewDate.getUTCFullYear(),
11704 month = this.viewDate.getUTCMonth();
11706 if (className.indexOf('old') !== -1) {
11713 } else if (className.indexOf('new') !== -1) {
11721 this.date = this.UTCDate(year, month, day,0,0,0,0);
11722 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
11724 this.setValue(this.formatDate(this.date));
11731 setStartDate: function(startDate){
11732 this.startDate = startDate || -Infinity;
11733 if (this.startDate !== -Infinity) {
11734 this.startDate = this.parseDate(this.startDate);
11737 this.updateNavArrows();
11740 setEndDate: function(endDate){
11741 this.endDate = endDate || Infinity;
11742 if (this.endDate !== Infinity) {
11743 this.endDate = this.parseDate(this.endDate);
11746 this.updateNavArrows();
11749 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
11750 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
11751 if (typeof(this.daysOfWeekDisabled) !== 'object') {
11752 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
11754 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
11755 return parseInt(d, 10);
11758 this.updateNavArrows();
11761 updateNavArrows: function() {
11762 var d = new Date(this.viewDate),
11763 year = d.getUTCFullYear(),
11764 month = d.getUTCMonth();
11766 Roo.each(this.picker().select('.prev', true).elements, function(v){
11768 switch (this.viewMode) {
11771 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
11777 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
11784 Roo.each(this.picker().select('.next', true).elements, function(v){
11786 switch (this.viewMode) {
11789 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
11795 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
11803 moveMonth: function(date, dir){
11804 if (!dir) return date;
11805 var new_date = new Date(date.valueOf()),
11806 day = new_date.getUTCDate(),
11807 month = new_date.getUTCMonth(),
11808 mag = Math.abs(dir),
11810 dir = dir > 0 ? 1 : -1;
11813 // If going back one month, make sure month is not current month
11814 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
11816 return new_date.getUTCMonth() == month;
11818 // If going forward one month, make sure month is as expected
11819 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
11821 return new_date.getUTCMonth() != new_month;
11823 new_month = month + dir;
11824 new_date.setUTCMonth(new_month);
11825 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
11826 if (new_month < 0 || new_month > 11)
11827 new_month = (new_month + 12) % 12;
11829 // For magnitudes >1, move one month at a time...
11830 for (var i=0; i<mag; i++)
11831 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
11832 new_date = this.moveMonth(new_date, dir);
11833 // ...then reset the day, keeping it in the new month
11834 new_month = new_date.getUTCMonth();
11835 new_date.setUTCDate(day);
11837 return new_month != new_date.getUTCMonth();
11840 // Common date-resetting loop -- if date is beyond end of month, make it
11843 new_date.setUTCDate(--day);
11844 new_date.setUTCMonth(new_month);
11849 moveYear: function(date, dir){
11850 return this.moveMonth(date, dir*12);
11853 dateWithinRange: function(date){
11854 return date >= this.startDate && date <= this.endDate;
11857 remove: function() {
11858 this.picker().remove();
11861 onIncrementHours: function()
11863 this.time.add(Date.HOUR, 1);
11867 onDecrementHours: function()
11869 this.time.add(Date.HOUR, -1);
11873 onIncrementMinutes: function()
11875 this.time.add(Date.MINUTE, 1);
11879 onDecrementMinutes: function()
11881 this.time.add(Date.MINUTE, -1);
11885 onTogglePeriod: function()
11887 Roo.log(this.time);
11889 if(this.time.format('A') === 'PM'){
11893 this.time.add(Date.HOUR, h);
11900 Roo.apply(Roo.bootstrap.DateField, {
11911 html: '<i class="icon-arrow-left"/>'
11921 html: '<i class="icon-arrow-right"/>'
11957 cls: 'picker-switch-icon glyphicon'
11969 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
11970 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
11971 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
11972 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
11973 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
11991 navFnc: 'FullYear',
11996 navFnc: 'FullYear',
12002 Roo.apply(Roo.bootstrap.DateField, {
12006 cls: 'datepicker dropdown-menu',
12010 cls: 'datepicker-days',
12014 cls: 'table-condensed',
12016 Roo.bootstrap.DateField.head,
12020 Roo.bootstrap.DateField.footer
12027 cls: 'datepicker-months',
12031 cls: 'table-condensed',
12033 Roo.bootstrap.DateField.head,
12034 Roo.bootstrap.DateField.content
12035 // Roo.bootstrap.DateField.footer
12042 cls: 'datepicker-years',
12046 cls: 'table-condensed',
12048 Roo.bootstrap.DateField.head,
12049 Roo.bootstrap.DateField.content
12050 // Roo.bootstrap.DateField.footer
12057 cls: 'datepicker-time',
12061 cls: 'table-condensed',
12063 Roo.bootstrap.DateField.content,
12064 Roo.bootstrap.DateField.footer
12083 * @class Roo.bootstrap.CheckBox
12084 * @extends Roo.bootstrap.Input
12085 * Bootstrap CheckBox class
12087 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
12088 * @cfg {String} boxLabel The text that appears beside the checkbox
12089 * @cfg {Boolean} checked initnal the element
12092 * Create a new CheckBox
12093 * @param {Object} config The config object
12096 Roo.bootstrap.CheckBox = function(config){
12097 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
12102 * Fires when the element is checked or unchecked.
12103 * @param {Roo.bootstrap.CheckBox} this This input
12104 * @param {Boolean} checked The new checked value
12110 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
12112 inputType: 'checkbox',
12118 getAutoCreate : function()
12120 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12126 cfg.cls = 'form-group' //input-group
12131 type : this.inputType,
12132 value : (!this.checked) ? this.valueOff : this.value,
12134 placeholder : this.placeholder || ''
12138 if (this.disabled) {
12139 input.disabled=true;
12143 input.checked = this.checked;
12147 input.name = this.name;
12151 input.cls += ' input-' + this.size;
12155 ['xs','sm','md','lg'].map(function(size){
12156 if (settings[size]) {
12157 cfg.cls += ' col-' + size + '-' + settings[size];
12161 var inputblock = input;
12163 if (this.before || this.after) {
12166 cls : 'input-group',
12170 inputblock.cn.push({
12172 cls : 'input-group-addon',
12176 inputblock.cn.push(input);
12178 inputblock.cn.push({
12180 cls : 'input-group-addon',
12187 if (align ==='left' && this.fieldLabel.length) {
12188 Roo.log("left and has label");
12194 cls : 'control-label col-md-' + this.labelWidth,
12195 html : this.fieldLabel
12199 cls : "col-md-" + (12 - this.labelWidth),
12206 } else if ( this.fieldLabel.length) {
12213 cls: 'control-label box-input-label',
12214 //cls : 'input-group-addon',
12215 html : this.fieldLabel
12225 Roo.log(" no label && no align");
12240 html: this.boxLabel
12249 * return the real input element.
12251 inputEl: function ()
12253 return this.el.select('input.form-box',true).first();
12256 initEvents : function()
12258 Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
12260 this.inputEl().on('click', this.onClick, this);
12264 onClick : function()
12266 this.setChecked(!this.checked);
12269 setChecked : function(state,suppressEvent)
12271 this.checked = state;
12273 if(suppressEvent !== true){
12274 this.fireEvent('check', this, state);
12277 this.inputEl().dom.value = state ? this.value : this.valueOff;
12291 * @class Roo.bootstrap.Radio
12292 * @extends Roo.bootstrap.CheckBox
12293 * Bootstrap Radio class
12296 * Create a new Radio
12297 * @param {Object} config The config object
12300 Roo.bootstrap.Radio = function(config){
12301 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
12305 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
12307 inputType: 'radio',
12309 getAutoCreate : function()
12311 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12317 cfg.cls = 'form-group' //input-group
12322 type : this.inputType,
12323 value : (!this.checked) ? this.valueOff : this.value,
12325 placeholder : this.placeholder || ''
12329 if (this.disabled) {
12330 input.disabled=true;
12334 input.checked = this.checked;
12338 input.name = this.name;
12342 input.cls += ' input-' + this.size;
12346 ['xs','sm','md','lg'].map(function(size){
12347 if (settings[size]) {
12348 cfg.cls += ' col-' + size + '-' + settings[size];
12352 var inputblock = input;
12354 if (this.before || this.after) {
12357 cls : 'input-group',
12361 inputblock.cn.push({
12363 cls : 'input-group-addon',
12367 inputblock.cn.push(input);
12369 inputblock.cn.push({
12371 cls : 'input-group-addon',
12378 if (align ==='left' && this.fieldLabel.length) {
12379 Roo.log("left and has label");
12385 cls : 'control-label col-md-' + this.labelWidth,
12386 html : this.fieldLabel
12390 cls : "col-md-" + (12 - this.labelWidth),
12397 } else if ( this.fieldLabel.length) {
12404 cls: 'control-label box-input-label',
12405 //cls : 'input-group-addon',
12406 html : this.fieldLabel
12416 Roo.log(" no label && no align");
12431 html: this.boxLabel
12439 onClick : function()
12441 this.setChecked(true);
12444 setChecked : function(state,suppressEvent)
12446 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12450 this.checked = state;
12452 if(suppressEvent !== true){
12453 this.fireEvent('check', this, state);
12456 this.inputEl().dom.value = state ? this.value : this.valueOff;
12460 getGroupValue : function()
12462 if(typeof(this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true)) == 'undefined'){
12466 return this.inputEl().up('form').child('input[name='+this.inputEl().dom.name+']:checked', true).value;
12470 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
12471 * @return {Mixed} value The field value
12473 getValue : function(){
12474 return this.getGroupValue();
12488 * @class Roo.bootstrap.HtmlEditor
12489 * @extends Roo.bootstrap.Component
12490 * Bootstrap HtmlEditor class
12493 * Create a new HtmlEditor
12494 * @param {Object} config The config object
12497 Roo.bootstrap.HtmlEditor = function(config){
12498 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
12499 if (!this.toolbars) {
12500 this.toolbars = [];
12502 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
12505 * @event initialize
12506 * Fires when the editor is fully initialized (including the iframe)
12507 * @param {HtmlEditor} this
12512 * Fires when the editor is first receives the focus. Any insertion must wait
12513 * until after this event.
12514 * @param {HtmlEditor} this
12518 * @event beforesync
12519 * Fires before the textarea is updated with content from the editor iframe. Return false
12520 * to cancel the sync.
12521 * @param {HtmlEditor} this
12522 * @param {String} html
12526 * @event beforepush
12527 * Fires before the iframe editor is updated with content from the textarea. Return false
12528 * to cancel the push.
12529 * @param {HtmlEditor} this
12530 * @param {String} html
12535 * Fires when the textarea is updated with content from the editor iframe.
12536 * @param {HtmlEditor} this
12537 * @param {String} html
12542 * Fires when the iframe editor is updated with content from the textarea.
12543 * @param {HtmlEditor} this
12544 * @param {String} html
12548 * @event editmodechange
12549 * Fires when the editor switches edit modes
12550 * @param {HtmlEditor} this
12551 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
12553 editmodechange: true,
12555 * @event editorevent
12556 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
12557 * @param {HtmlEditor} this
12561 * @event firstfocus
12562 * Fires when on first focus - needed by toolbars..
12563 * @param {HtmlEditor} this
12568 * Auto save the htmlEditor value as a file into Events
12569 * @param {HtmlEditor} this
12573 * @event savedpreview
12574 * preview the saved version of htmlEditor
12575 * @param {HtmlEditor} this
12582 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
12586 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
12591 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
12596 * @cfg {Number} height (in pixels)
12600 * @cfg {Number} width (in pixels)
12605 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
12608 stylesheets: false,
12613 // private properties
12614 validationEvent : false,
12616 initialized : false,
12619 onFocus : Roo.emptyFn,
12621 hideMode:'offsets',
12624 tbContainer : false,
12626 toolbarContainer :function() {
12627 return this.wrap.select('.x-html-editor-tb',true).first();
12631 * Protected method that will not generally be called directly. It
12632 * is called when the editor creates its toolbar. Override this method if you need to
12633 * add custom toolbar buttons.
12634 * @param {HtmlEditor} editor
12636 createToolbar : function(){
12638 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
12639 this.toolbars[0].render(this.toolbarContainer());
12641 Roo.log("create toolbars");
12643 if (!editor.toolbars || !editor.toolbars.length) {
12644 editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
12647 for (var i =0 ; i < editor.toolbars.length;i++) {
12648 editor.toolbars[i] = Roo.factory(
12649 typeof(editor.toolbars[i]) == 'string' ?
12650 { xtype: editor.toolbars[i]} : editor.toolbars[i],
12651 Roo.bootstrap.HtmlEditor);
12652 editor.toolbars[i].init(editor);
12660 onRender : function(ct, position)
12662 // Roo.log("Call onRender: " + this.xtype);
12664 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
12666 this.wrap = this.inputEl().wrap({
12667 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
12670 this.editorcore.onRender(ct, position);
12672 if (this.resizable) {
12673 this.resizeEl = new Roo.Resizable(this.wrap, {
12677 minHeight : this.height,
12678 height: this.height,
12679 handles : this.resizable,
12682 resize : function(r, w, h) {
12683 _t.onResize(w,h); // -something
12689 this.createToolbar(this);
12693 this.setSize(this.wrap.getSize());
12695 if (this.resizeEl) {
12696 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
12697 // should trigger onReize..
12700 // if(this.autosave && this.w){
12701 // this.autoSaveFn = setInterval(this.autosave, 1000);
12706 onResize : function(w, h)
12708 Roo.log('resize: ' +w + ',' + h );
12709 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
12713 if(this.inputEl() ){
12714 if(typeof w == 'number'){
12715 var aw = w - this.wrap.getFrameWidth('lr');
12716 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
12719 if(typeof h == 'number'){
12720 var tbh = -11; // fixme it needs to tool bar size!
12721 for (var i =0; i < this.toolbars.length;i++) {
12722 // fixme - ask toolbars for heights?
12723 tbh += this.toolbars[i].el.getHeight();
12724 //if (this.toolbars[i].footer) {
12725 // tbh += this.toolbars[i].footer.el.getHeight();
12733 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
12734 ah -= 5; // knock a few pixes off for look..
12735 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
12739 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
12740 this.editorcore.onResize(ew,eh);
12745 * Toggles the editor between standard and source edit mode.
12746 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
12748 toggleSourceEdit : function(sourceEditMode)
12750 this.editorcore.toggleSourceEdit(sourceEditMode);
12752 if(this.editorcore.sourceEditMode){
12753 Roo.log('editor - showing textarea');
12756 // Roo.log(this.syncValue());
12757 this.editorcore.syncValue();
12758 this.inputEl().removeClass('hide');
12759 this.inputEl().dom.removeAttribute('tabIndex');
12760 this.inputEl().focus();
12762 Roo.log('editor - hiding textarea');
12764 // Roo.log(this.pushValue());
12765 this.editorcore.pushValue();
12767 this.inputEl().addClass('hide');
12768 this.inputEl().dom.setAttribute('tabIndex', -1);
12769 //this.deferFocus();
12772 this.setSize(this.wrap.getSize());
12773 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
12776 // private (for BoxComponent)
12777 adjustSize : Roo.BoxComponent.prototype.adjustSize,
12779 // private (for BoxComponent)
12780 getResizeEl : function(){
12784 // private (for BoxComponent)
12785 getPositionEl : function(){
12790 initEvents : function(){
12791 this.originalValue = this.getValue();
12795 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
12798 markInvalid : Roo.emptyFn,
12800 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
12803 clearInvalid : Roo.emptyFn,
12805 setValue : function(v){
12806 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
12807 this.editorcore.pushValue();
12812 deferFocus : function(){
12813 this.focus.defer(10, this);
12817 focus : function(){
12818 this.editorcore.focus();
12824 onDestroy : function(){
12830 for (var i =0; i < this.toolbars.length;i++) {
12831 // fixme - ask toolbars for heights?
12832 this.toolbars[i].onDestroy();
12835 this.wrap.dom.innerHTML = '';
12836 this.wrap.remove();
12841 onFirstFocus : function(){
12842 //Roo.log("onFirstFocus");
12843 this.editorcore.onFirstFocus();
12844 for (var i =0; i < this.toolbars.length;i++) {
12845 this.toolbars[i].onFirstFocus();
12851 syncValue : function()
12853 this.editorcore.syncValue();
12857 // hide stuff that is not compatible
12871 * @event specialkey
12875 * @cfg {String} fieldClass @hide
12878 * @cfg {String} focusClass @hide
12881 * @cfg {String} autoCreate @hide
12884 * @cfg {String} inputType @hide
12887 * @cfg {String} invalidClass @hide
12890 * @cfg {String} invalidText @hide
12893 * @cfg {String} msgFx @hide
12896 * @cfg {String} validateOnBlur @hide
12906 * @class Roo.bootstrap.Table.AbstractSelectionModel
12907 * @extends Roo.util.Observable
12908 * Abstract base class for grid SelectionModels. It provides the interface that should be
12909 * implemented by descendant classes. This class should not be directly instantiated.
12912 Roo.bootstrap.Table.AbstractSelectionModel = function(){
12913 this.locked = false;
12914 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
12918 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
12919 /** @ignore Called by the grid automatically. Do not call directly. */
12920 init : function(grid){
12926 * Locks the selections.
12929 this.locked = true;
12933 * Unlocks the selections.
12935 unlock : function(){
12936 this.locked = false;
12940 * Returns true if the selections are locked.
12941 * @return {Boolean}
12943 isLocked : function(){
12944 return this.locked;
12948 * @class Roo.bootstrap.Table.ColumnModel
12949 * @extends Roo.util.Observable
12950 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
12951 * the columns in the table.
12954 * @param {Object} config An Array of column config objects. See this class's
12955 * config objects for details.
12957 Roo.bootstrap.Table.ColumnModel = function(config){
12959 * The config passed into the constructor
12961 this.config = config;
12964 // if no id, create one
12965 // if the column does not have a dataIndex mapping,
12966 // map it to the order it is in the config
12967 for(var i = 0, len = config.length; i < len; i++){
12969 if(typeof c.dataIndex == "undefined"){
12972 if(typeof c.renderer == "string"){
12973 c.renderer = Roo.util.Format[c.renderer];
12975 if(typeof c.id == "undefined"){
12978 // if(c.editor && c.editor.xtype){
12979 // c.editor = Roo.factory(c.editor, Roo.grid);
12981 // if(c.editor && c.editor.isFormField){
12982 // c.editor = new Roo.grid.GridEditor(c.editor);
12985 this.lookup[c.id] = c;
12989 * The width of columns which have no width specified (defaults to 100)
12992 this.defaultWidth = 100;
12995 * Default sortable of columns which have no sortable specified (defaults to false)
12998 this.defaultSortable = false;
13002 * @event widthchange
13003 * Fires when the width of a column changes.
13004 * @param {ColumnModel} this
13005 * @param {Number} columnIndex The column index
13006 * @param {Number} newWidth The new width
13008 "widthchange": true,
13010 * @event headerchange
13011 * Fires when the text of a header changes.
13012 * @param {ColumnModel} this
13013 * @param {Number} columnIndex The column index
13014 * @param {Number} newText The new header text
13016 "headerchange": true,
13018 * @event hiddenchange
13019 * Fires when a column is hidden or "unhidden".
13020 * @param {ColumnModel} this
13021 * @param {Number} columnIndex The column index
13022 * @param {Boolean} hidden true if hidden, false otherwise
13024 "hiddenchange": true,
13026 * @event columnmoved
13027 * Fires when a column is moved.
13028 * @param {ColumnModel} this
13029 * @param {Number} oldIndex
13030 * @param {Number} newIndex
13032 "columnmoved" : true,
13034 * @event columlockchange
13035 * Fires when a column's locked state is changed
13036 * @param {ColumnModel} this
13037 * @param {Number} colIndex
13038 * @param {Boolean} locked true if locked
13040 "columnlockchange" : true
13042 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
13044 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
13046 * @cfg {String} header The header text to display in the Grid view.
13049 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
13050 * {@link Roo.data.Record} definition from which to draw the column's value. If not
13051 * specified, the column's index is used as an index into the Record's data Array.
13054 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
13055 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
13058 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
13059 * Defaults to the value of the {@link #defaultSortable} property.
13060 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
13063 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
13066 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
13069 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
13072 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
13075 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
13076 * given the cell's data value. See {@link #setRenderer}. If not specified, the
13077 * default renderer uses the raw data value.
13080 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
13084 * Returns the id of the column at the specified index.
13085 * @param {Number} index The column index
13086 * @return {String} the id
13088 getColumnId : function(index){
13089 return this.config[index].id;
13093 * Returns the column for a specified id.
13094 * @param {String} id The column id
13095 * @return {Object} the column
13097 getColumnById : function(id){
13098 return this.lookup[id];
13103 * Returns the column for a specified dataIndex.
13104 * @param {String} dataIndex The column dataIndex
13105 * @return {Object|Boolean} the column or false if not found
13107 getColumnByDataIndex: function(dataIndex){
13108 var index = this.findColumnIndex(dataIndex);
13109 return index > -1 ? this.config[index] : false;
13113 * Returns the index for a specified column id.
13114 * @param {String} id The column id
13115 * @return {Number} the index, or -1 if not found
13117 getIndexById : function(id){
13118 for(var i = 0, len = this.config.length; i < len; i++){
13119 if(this.config[i].id == id){
13127 * Returns the index for a specified column dataIndex.
13128 * @param {String} dataIndex The column dataIndex
13129 * @return {Number} the index, or -1 if not found
13132 findColumnIndex : function(dataIndex){
13133 for(var i = 0, len = this.config.length; i < len; i++){
13134 if(this.config[i].dataIndex == dataIndex){
13142 moveColumn : function(oldIndex, newIndex){
13143 var c = this.config[oldIndex];
13144 this.config.splice(oldIndex, 1);
13145 this.config.splice(newIndex, 0, c);
13146 this.dataMap = null;
13147 this.fireEvent("columnmoved", this, oldIndex, newIndex);
13150 isLocked : function(colIndex){
13151 return this.config[colIndex].locked === true;
13154 setLocked : function(colIndex, value, suppressEvent){
13155 if(this.isLocked(colIndex) == value){
13158 this.config[colIndex].locked = value;
13159 if(!suppressEvent){
13160 this.fireEvent("columnlockchange", this, colIndex, value);
13164 getTotalLockedWidth : function(){
13165 var totalWidth = 0;
13166 for(var i = 0; i < this.config.length; i++){
13167 if(this.isLocked(i) && !this.isHidden(i)){
13168 this.totalWidth += this.getColumnWidth(i);
13174 getLockedCount : function(){
13175 for(var i = 0, len = this.config.length; i < len; i++){
13176 if(!this.isLocked(i)){
13183 * Returns the number of columns.
13186 getColumnCount : function(visibleOnly){
13187 if(visibleOnly === true){
13189 for(var i = 0, len = this.config.length; i < len; i++){
13190 if(!this.isHidden(i)){
13196 return this.config.length;
13200 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
13201 * @param {Function} fn
13202 * @param {Object} scope (optional)
13203 * @return {Array} result
13205 getColumnsBy : function(fn, scope){
13207 for(var i = 0, len = this.config.length; i < len; i++){
13208 var c = this.config[i];
13209 if(fn.call(scope||this, c, i) === true){
13217 * Returns true if the specified column is sortable.
13218 * @param {Number} col The column index
13219 * @return {Boolean}
13221 isSortable : function(col){
13222 if(typeof this.config[col].sortable == "undefined"){
13223 return this.defaultSortable;
13225 return this.config[col].sortable;
13229 * Returns the rendering (formatting) function defined for the column.
13230 * @param {Number} col The column index.
13231 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
13233 getRenderer : function(col){
13234 if(!this.config[col].renderer){
13235 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
13237 return this.config[col].renderer;
13241 * Sets the rendering (formatting) function for a column.
13242 * @param {Number} col The column index
13243 * @param {Function} fn The function to use to process the cell's raw data
13244 * to return HTML markup for the grid view. The render function is called with
13245 * the following parameters:<ul>
13246 * <li>Data value.</li>
13247 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
13248 * <li>css A CSS style string to apply to the table cell.</li>
13249 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
13250 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
13251 * <li>Row index</li>
13252 * <li>Column index</li>
13253 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
13255 setRenderer : function(col, fn){
13256 this.config[col].renderer = fn;
13260 * Returns the width for the specified column.
13261 * @param {Number} col The column index
13264 getColumnWidth : function(col){
13265 return this.config[col].width * 1 || this.defaultWidth;
13269 * Sets the width for a column.
13270 * @param {Number} col The column index
13271 * @param {Number} width The new width
13273 setColumnWidth : function(col, width, suppressEvent){
13274 this.config[col].width = width;
13275 this.totalWidth = null;
13276 if(!suppressEvent){
13277 this.fireEvent("widthchange", this, col, width);
13282 * Returns the total width of all columns.
13283 * @param {Boolean} includeHidden True to include hidden column widths
13286 getTotalWidth : function(includeHidden){
13287 if(!this.totalWidth){
13288 this.totalWidth = 0;
13289 for(var i = 0, len = this.config.length; i < len; i++){
13290 if(includeHidden || !this.isHidden(i)){
13291 this.totalWidth += this.getColumnWidth(i);
13295 return this.totalWidth;
13299 * Returns the header for the specified column.
13300 * @param {Number} col The column index
13303 getColumnHeader : function(col){
13304 return this.config[col].header;
13308 * Sets the header for a column.
13309 * @param {Number} col The column index
13310 * @param {String} header The new header
13312 setColumnHeader : function(col, header){
13313 this.config[col].header = header;
13314 this.fireEvent("headerchange", this, col, header);
13318 * Returns the tooltip for the specified column.
13319 * @param {Number} col The column index
13322 getColumnTooltip : function(col){
13323 return this.config[col].tooltip;
13326 * Sets the tooltip for a column.
13327 * @param {Number} col The column index
13328 * @param {String} tooltip The new tooltip
13330 setColumnTooltip : function(col, tooltip){
13331 this.config[col].tooltip = tooltip;
13335 * Returns the dataIndex for the specified column.
13336 * @param {Number} col The column index
13339 getDataIndex : function(col){
13340 return this.config[col].dataIndex;
13344 * Sets the dataIndex for a column.
13345 * @param {Number} col The column index
13346 * @param {Number} dataIndex The new dataIndex
13348 setDataIndex : function(col, dataIndex){
13349 this.config[col].dataIndex = dataIndex;
13355 * Returns true if the cell is editable.
13356 * @param {Number} colIndex The column index
13357 * @param {Number} rowIndex The row index
13358 * @return {Boolean}
13360 isCellEditable : function(colIndex, rowIndex){
13361 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
13365 * Returns the editor defined for the cell/column.
13366 * return false or null to disable editing.
13367 * @param {Number} colIndex The column index
13368 * @param {Number} rowIndex The row index
13371 getCellEditor : function(colIndex, rowIndex){
13372 return this.config[colIndex].editor;
13376 * Sets if a column is editable.
13377 * @param {Number} col The column index
13378 * @param {Boolean} editable True if the column is editable
13380 setEditable : function(col, editable){
13381 this.config[col].editable = editable;
13386 * Returns true if the column is hidden.
13387 * @param {Number} colIndex The column index
13388 * @return {Boolean}
13390 isHidden : function(colIndex){
13391 return this.config[colIndex].hidden;
13396 * Returns true if the column width cannot be changed
13398 isFixed : function(colIndex){
13399 return this.config[colIndex].fixed;
13403 * Returns true if the column can be resized
13404 * @return {Boolean}
13406 isResizable : function(colIndex){
13407 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
13410 * Sets if a column is hidden.
13411 * @param {Number} colIndex The column index
13412 * @param {Boolean} hidden True if the column is hidden
13414 setHidden : function(colIndex, hidden){
13415 this.config[colIndex].hidden = hidden;
13416 this.totalWidth = null;
13417 this.fireEvent("hiddenchange", this, colIndex, hidden);
13421 * Sets the editor for a column.
13422 * @param {Number} col The column index
13423 * @param {Object} editor The editor object
13425 setEditor : function(col, editor){
13426 this.config[col].editor = editor;
13430 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
13431 if(typeof value == "string" && value.length < 1){
13437 // Alias for backwards compatibility
13438 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
13441 * @extends Roo.bootstrap.Table.AbstractSelectionModel
13442 * @class Roo.bootstrap.Table.RowSelectionModel
13443 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
13444 * It supports multiple selections and keyboard selection/navigation.
13446 * @param {Object} config
13449 Roo.bootstrap.Table.RowSelectionModel = function(config){
13450 Roo.apply(this, config);
13451 this.selections = new Roo.util.MixedCollection(false, function(o){
13456 this.lastActive = false;
13460 * @event selectionchange
13461 * Fires when the selection changes
13462 * @param {SelectionModel} this
13464 "selectionchange" : true,
13466 * @event afterselectionchange
13467 * Fires after the selection changes (eg. by key press or clicking)
13468 * @param {SelectionModel} this
13470 "afterselectionchange" : true,
13472 * @event beforerowselect
13473 * Fires when a row is selected being selected, return false to cancel.
13474 * @param {SelectionModel} this
13475 * @param {Number} rowIndex The selected index
13476 * @param {Boolean} keepExisting False if other selections will be cleared
13478 "beforerowselect" : true,
13481 * Fires when a row is selected.
13482 * @param {SelectionModel} this
13483 * @param {Number} rowIndex The selected index
13484 * @param {Roo.data.Record} r The record
13486 "rowselect" : true,
13488 * @event rowdeselect
13489 * Fires when a row is deselected.
13490 * @param {SelectionModel} this
13491 * @param {Number} rowIndex The selected index
13493 "rowdeselect" : true
13495 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
13496 this.locked = false;
13499 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
13501 * @cfg {Boolean} singleSelect
13502 * True to allow selection of only one row at a time (defaults to false)
13504 singleSelect : false,
13507 initEvents : function(){
13509 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
13510 this.grid.on("mousedown", this.handleMouseDown, this);
13511 }else{ // allow click to work like normal
13512 this.grid.on("rowclick", this.handleDragableRowClick, this);
13515 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
13516 "up" : function(e){
13518 this.selectPrevious(e.shiftKey);
13519 }else if(this.last !== false && this.lastActive !== false){
13520 var last = this.last;
13521 this.selectRange(this.last, this.lastActive-1);
13522 this.grid.getView().focusRow(this.lastActive);
13523 if(last !== false){
13527 this.selectFirstRow();
13529 this.fireEvent("afterselectionchange", this);
13531 "down" : function(e){
13533 this.selectNext(e.shiftKey);
13534 }else if(this.last !== false && this.lastActive !== false){
13535 var last = this.last;
13536 this.selectRange(this.last, this.lastActive+1);
13537 this.grid.getView().focusRow(this.lastActive);
13538 if(last !== false){
13542 this.selectFirstRow();
13544 this.fireEvent("afterselectionchange", this);
13549 var view = this.grid.view;
13550 view.on("refresh", this.onRefresh, this);
13551 view.on("rowupdated", this.onRowUpdated, this);
13552 view.on("rowremoved", this.onRemove, this);
13556 onRefresh : function(){
13557 var ds = this.grid.dataSource, i, v = this.grid.view;
13558 var s = this.selections;
13559 s.each(function(r){
13560 if((i = ds.indexOfId(r.id)) != -1){
13569 onRemove : function(v, index, r){
13570 this.selections.remove(r);
13574 onRowUpdated : function(v, index, r){
13575 if(this.isSelected(r)){
13576 v.onRowSelect(index);
13582 * @param {Array} records The records to select
13583 * @param {Boolean} keepExisting (optional) True to keep existing selections
13585 selectRecords : function(records, keepExisting){
13587 this.clearSelections();
13589 var ds = this.grid.dataSource;
13590 for(var i = 0, len = records.length; i < len; i++){
13591 this.selectRow(ds.indexOf(records[i]), true);
13596 * Gets the number of selected rows.
13599 getCount : function(){
13600 return this.selections.length;
13604 * Selects the first row in the grid.
13606 selectFirstRow : function(){
13611 * Select the last row.
13612 * @param {Boolean} keepExisting (optional) True to keep existing selections
13614 selectLastRow : function(keepExisting){
13615 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
13619 * Selects the row immediately following the last selected row.
13620 * @param {Boolean} keepExisting (optional) True to keep existing selections
13622 selectNext : function(keepExisting){
13623 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
13624 this.selectRow(this.last+1, keepExisting);
13625 this.grid.getView().focusRow(this.last);
13630 * Selects the row that precedes the last selected row.
13631 * @param {Boolean} keepExisting (optional) True to keep existing selections
13633 selectPrevious : function(keepExisting){
13635 this.selectRow(this.last-1, keepExisting);
13636 this.grid.getView().focusRow(this.last);
13641 * Returns the selected records
13642 * @return {Array} Array of selected records
13644 getSelections : function(){
13645 return [].concat(this.selections.items);
13649 * Returns the first selected record.
13652 getSelected : function(){
13653 return this.selections.itemAt(0);
13658 * Clears all selections.
13660 clearSelections : function(fast){
13661 if(this.locked) return;
13663 var ds = this.grid.dataSource;
13664 var s = this.selections;
13665 s.each(function(r){
13666 this.deselectRow(ds.indexOfId(r.id));
13670 this.selections.clear();
13677 * Selects all rows.
13679 selectAll : function(){
13680 if(this.locked) return;
13681 this.selections.clear();
13682 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
13683 this.selectRow(i, true);
13688 * Returns True if there is a selection.
13689 * @return {Boolean}
13691 hasSelection : function(){
13692 return this.selections.length > 0;
13696 * Returns True if the specified row is selected.
13697 * @param {Number/Record} record The record or index of the record to check
13698 * @return {Boolean}
13700 isSelected : function(index){
13701 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
13702 return (r && this.selections.key(r.id) ? true : false);
13706 * Returns True if the specified record id is selected.
13707 * @param {String} id The id of record to check
13708 * @return {Boolean}
13710 isIdSelected : function(id){
13711 return (this.selections.key(id) ? true : false);
13715 handleMouseDown : function(e, t){
13716 var view = this.grid.getView(), rowIndex;
13717 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
13720 if(e.shiftKey && this.last !== false){
13721 var last = this.last;
13722 this.selectRange(last, rowIndex, e.ctrlKey);
13723 this.last = last; // reset the last
13724 view.focusRow(rowIndex);
13726 var isSelected = this.isSelected(rowIndex);
13727 if(e.button !== 0 && isSelected){
13728 view.focusRow(rowIndex);
13729 }else if(e.ctrlKey && isSelected){
13730 this.deselectRow(rowIndex);
13731 }else if(!isSelected){
13732 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
13733 view.focusRow(rowIndex);
13736 this.fireEvent("afterselectionchange", this);
13739 handleDragableRowClick : function(grid, rowIndex, e)
13741 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
13742 this.selectRow(rowIndex, false);
13743 grid.view.focusRow(rowIndex);
13744 this.fireEvent("afterselectionchange", this);
13749 * Selects multiple rows.
13750 * @param {Array} rows Array of the indexes of the row to select
13751 * @param {Boolean} keepExisting (optional) True to keep existing selections
13753 selectRows : function(rows, keepExisting){
13755 this.clearSelections();
13757 for(var i = 0, len = rows.length; i < len; i++){
13758 this.selectRow(rows[i], true);
13763 * Selects a range of rows. All rows in between startRow and endRow are also selected.
13764 * @param {Number} startRow The index of the first row in the range
13765 * @param {Number} endRow The index of the last row in the range
13766 * @param {Boolean} keepExisting (optional) True to retain existing selections
13768 selectRange : function(startRow, endRow, keepExisting){
13769 if(this.locked) return;
13771 this.clearSelections();
13773 if(startRow <= endRow){
13774 for(var i = startRow; i <= endRow; i++){
13775 this.selectRow(i, true);
13778 for(var i = startRow; i >= endRow; i--){
13779 this.selectRow(i, true);
13785 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
13786 * @param {Number} startRow The index of the first row in the range
13787 * @param {Number} endRow The index of the last row in the range
13789 deselectRange : function(startRow, endRow, preventViewNotify){
13790 if(this.locked) return;
13791 for(var i = startRow; i <= endRow; i++){
13792 this.deselectRow(i, preventViewNotify);
13798 * @param {Number} row The index of the row to select
13799 * @param {Boolean} keepExisting (optional) True to keep existing selections
13801 selectRow : function(index, keepExisting, preventViewNotify){
13802 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
13803 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
13804 if(!keepExisting || this.singleSelect){
13805 this.clearSelections();
13807 var r = this.grid.dataSource.getAt(index);
13808 this.selections.add(r);
13809 this.last = this.lastActive = index;
13810 if(!preventViewNotify){
13811 this.grid.getView().onRowSelect(index);
13813 this.fireEvent("rowselect", this, index, r);
13814 this.fireEvent("selectionchange", this);
13820 * @param {Number} row The index of the row to deselect
13822 deselectRow : function(index, preventViewNotify){
13823 if(this.locked) return;
13824 if(this.last == index){
13827 if(this.lastActive == index){
13828 this.lastActive = false;
13830 var r = this.grid.dataSource.getAt(index);
13831 this.selections.remove(r);
13832 if(!preventViewNotify){
13833 this.grid.getView().onRowDeselect(index);
13835 this.fireEvent("rowdeselect", this, index);
13836 this.fireEvent("selectionchange", this);
13840 restoreLast : function(){
13842 this.last = this._last;
13847 acceptsNav : function(row, col, cm){
13848 return !cm.isHidden(col) && cm.isCellEditable(col, row);
13852 onEditorKey : function(field, e){
13853 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
13858 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
13860 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
13862 }else if(k == e.ENTER && !e.ctrlKey){
13866 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
13868 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
13870 }else if(k == e.ESC){
13874 g.startEditing(newCell[0], newCell[1]);