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])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
300 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
305 onRender : function(ct, position){
308 //this.el.addClass([this.fieldClass, this.cls]);
326 * @class Roo.bootstrap.ButtonGroup
327 * @extends Roo.bootstrap.Component
328 * Bootstrap ButtonGroup class
329 * @cfg {String} size lg | sm | xs (default empty normal)
330 * @cfg {String} align vertical | justified (default none)
331 * @cfg {String} direction up | down (default down)
332 * @cfg {Boolean} toolbar false | true
333 * @cfg {Boolean} btn true | false
338 * @param {Object} config The config object
341 Roo.bootstrap.ButtonGroup = function(config){
342 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
345 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
353 getAutoCreate : function(){
359 cfg.html = this.html || cfg.html;
370 if (['vertical','justified'].indexOf(this.align)!==-1) {
371 cfg.cls = 'btn-group-' + this.align;
373 if (this.align == 'justified') {
374 console.log(this.items);
378 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
379 cfg.cls += ' btn-group-' + this.size;
382 if (this.direction == 'up') {
383 cfg.cls += ' dropup' ;
399 * @class Roo.bootstrap.Button
400 * @extends Roo.bootstrap.Component
401 * Bootstrap Button class
402 * @cfg {String} html The button content
403 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
404 * @cfg {String} size empty | lg | sm | xs
405 * @cfg {String} tag empty | a | input | submit
406 * @cfg {String} href empty or href
407 * @cfg {Boolean} disabled false | true
408 * @cfg {Boolean} isClose false | true
409 * @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
410 * @cfg {String} badge text for badge
411 * @cfg {String} theme default (or empty) | glow
412 * @cfg {Boolean} inverse false | true
413 * @cfg {Boolean} toggle false | true
414 * @cfg {String} ontext text for on toggle state
415 * @cfg {String} offtext text for off toggle state
416 * @cfg {Boolean} defaulton true | false
417 * @cfg {Boolean} preventDefault (true | false) default true
418 * @cfg {Boolean} removeClass true | false remove the standard class..
419 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
422 * Create a new button
423 * @param {Object} config The config object
427 Roo.bootstrap.Button = function(config){
428 Roo.bootstrap.Button.superclass.constructor.call(this, config);
433 * When a butotn is pressed
434 * @param {Roo.EventObject} e
439 * After the button has been toggles
440 * @param {Roo.EventObject} e
441 * @param {boolean} pressed (also available as button.pressed)
447 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
465 preventDefault: true,
474 getAutoCreate : function(){
482 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
483 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
488 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
490 if (this.toggle == true) {
493 cls: 'slider-frame roo-button',
498 'data-off-text':'OFF',
499 cls: 'slider-button',
505 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
506 cfg.cls += ' '+this.weight;
515 cfg["aria-hidden"] = true;
517 cfg.html = "×";
523 if (this.theme==='default') {
524 cfg.cls = 'btn roo-button';
526 //if (this.parentType != 'Navbar') {
527 this.weight = this.weight.length ? this.weight : 'default';
529 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
531 cfg.cls += ' btn-' + this.weight;
533 } else if (this.theme==='glow') {
536 cfg.cls = 'btn-glow roo-button';
538 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
540 cfg.cls += ' ' + this.weight;
546 this.cls += ' inverse';
551 cfg.cls += ' active';
555 cfg.disabled = 'disabled';
559 Roo.log('changing to ul' );
561 this.glyphicon = 'caret';
564 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
566 //gsRoo.log(this.parentType);
567 if (this.parentType === 'Navbar' && !this.parent().bar) {
568 Roo.log('changing to li?');
577 href : this.href || '#'
580 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
581 cfg.cls += ' dropdown';
588 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
590 if (this.glyphicon) {
591 cfg.html = ' ' + cfg.html;
596 cls: 'glyphicon glyphicon-' + this.glyphicon
606 // cfg.cls='btn roo-button';
610 var value = cfg.html;
615 cls: 'glyphicon glyphicon-' + this.glyphicon,
634 cfg.cls += ' dropdown';
635 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
638 if (cfg.tag !== 'a' && this.href !== '') {
639 throw "Tag must be a to set href.";
640 } else if (this.href.length > 0) {
641 cfg.href = this.href;
644 if(this.removeClass){
649 cfg.target = this.target;
654 initEvents: function() {
655 // Roo.log('init events?');
656 // Roo.log(this.el.dom);
657 if (this.el.hasClass('roo-button')) {
658 this.el.on('click', this.onClick, this);
660 this.el.select('.roo-button').on('click', this.onClick, this);
663 this.el.enableDisplayMode();
666 onClick : function(e)
672 Roo.log('button on click ');
673 if(this.preventDefault){
676 if (this.pressed === true || this.pressed === false) {
677 this.pressed = !this.pressed;
678 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
679 this.fireEvent('toggle', this, e, this.pressed);
683 this.fireEvent('click', this, e);
687 * Enables this button
691 this.disabled = false;
692 this.el.removeClass('disabled');
696 * Disable this button
700 this.disabled = true;
701 this.el.addClass('disabled');
704 * sets the active state on/off,
705 * @param {Boolean} state (optional) Force a particular state
707 setActive : function(v) {
709 this.el[v ? 'addClass' : 'removeClass']('active');
712 * toggles the current active state
714 toggleActive : function()
716 var active = this.el.hasClass('active');
717 this.setActive(!active);
721 setText : function(str)
723 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
746 * @class Roo.bootstrap.Column
747 * @extends Roo.bootstrap.Component
748 * Bootstrap Column class
749 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
750 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
751 * @cfg {Number} md colspan out of 12 for computer-sized screens
752 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
753 * @cfg {String} html content of column.
756 * Create a new Column
757 * @param {Object} config The config object
760 Roo.bootstrap.Column = function(config){
761 Roo.bootstrap.Column.superclass.constructor.call(this, config);
764 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
773 getAutoCreate : function(){
774 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
782 ['xs','sm','md','lg'].map(function(size){
783 if (settings[size]) {
784 cfg.cls += ' col-' + size + '-' + settings[size];
787 if (this.html.length) {
788 cfg.html = this.html;
807 * @class Roo.bootstrap.Container
808 * @extends Roo.bootstrap.Component
809 * Bootstrap Container class
810 * @cfg {Boolean} jumbotron is it a jumbotron element
811 * @cfg {String} html content of element
812 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
813 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
814 * @cfg {String} header content of header (for panel)
815 * @cfg {String} footer content of footer (for panel)
816 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
819 * Create a new Container
820 * @param {Object} config The config object
823 Roo.bootstrap.Container = function(config){
824 Roo.bootstrap.Container.superclass.constructor.call(this, config);
827 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
837 getChildContainer : function() {
843 if (this.panel.length) {
844 return this.el.select('.panel-body',true).first();
851 getAutoCreate : function(){
857 if (this.jumbotron) {
858 cfg.cls = 'jumbotron';
861 cfg.cls = this.cls + '';
864 if (this.sticky.length) {
866 var bd = Roo.get(document.body);
867 if (!bd.hasClass('bootstrap-sticky')) {
868 bd.addClass('bootstrap-sticky');
869 Roo.select('html',true).setStyle('height', '100%');
872 cfg.cls += 'bootstrap-sticky-' + this.sticky;
876 if (this.well.length) {
880 cfg.cls +=' well well-' +this.well;
890 if (this.panel.length) {
891 cfg.cls += ' panel panel-' + this.panel;
893 if (this.header.length) {
896 cls : 'panel-heading',
912 if (this.footer.length) {
914 cls : 'panel-footer',
922 body.html = this.html || cfg.html;
924 if (!cfg.cls.length) {
925 cfg.cls = 'container';
942 * @class Roo.bootstrap.Img
943 * @extends Roo.bootstrap.Component
944 * Bootstrap Img class
945 * @cfg {Boolean} imgResponsive false | true
946 * @cfg {String} border rounded | circle | thumbnail
947 * @cfg {String} src image source
948 * @cfg {String} alt image alternative text
949 * @cfg {String} href a tag href
950 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
954 * @param {Object} config The config object
957 Roo.bootstrap.Img = function(config){
958 Roo.bootstrap.Img.superclass.constructor.call(this, config);
964 * The img click event for the img.
965 * @param {Roo.EventObject} e
971 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
979 getAutoCreate : function(){
983 cls: (this.imgResponsive) ? 'img-responsive' : '',
987 cfg.html = this.html || cfg.html;
989 cfg.src = this.src || cfg.src;
991 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
992 cfg.cls += ' img-' + this.border;
1009 a.target = this.target;
1015 return (this.href) ? a : cfg;
1018 initEvents: function() {
1021 this.el.on('click', this.onClick, this);
1025 onClick : function(e)
1027 Roo.log('img onclick');
1028 this.fireEvent('click', this, e);
1041 * @class Roo.bootstrap.Header
1042 * @extends Roo.bootstrap.Component
1043 * Bootstrap Header class
1044 * @cfg {String} html content of header
1045 * @cfg {Number} level (1|2|3|4|5|6) default 1
1048 * Create a new Header
1049 * @param {Object} config The config object
1053 Roo.bootstrap.Header = function(config){
1054 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1057 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1065 getAutoCreate : function(){
1068 tag: 'h' + (1 *this.level),
1069 html: this.html || 'fill in html'
1081 * Ext JS Library 1.1.1
1082 * Copyright(c) 2006-2007, Ext JS, LLC.
1084 * Originally Released Under LGPL - original licence link has changed is not relivant.
1087 * <script type="text/javascript">
1091 * @class Roo.bootstrap.MenuMgr
1092 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1095 Roo.bootstrap.MenuMgr = function(){
1096 var menus, active, groups = {}, attached = false, lastShow = new Date();
1098 // private - called when first menu is created
1101 active = new Roo.util.MixedCollection();
1102 Roo.get(document).addKeyListener(27, function(){
1103 if(active.length > 0){
1111 if(active && active.length > 0){
1112 var c = active.clone();
1122 if(active.length < 1){
1123 Roo.get(document).un("mouseup", onMouseDown);
1131 var last = active.last();
1132 lastShow = new Date();
1135 Roo.get(document).on("mouseup", onMouseDown);
1140 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1141 m.parentMenu.activeChild = m;
1142 }else if(last && last.isVisible()){
1143 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1148 function onBeforeHide(m){
1150 m.activeChild.hide();
1152 if(m.autoHideTimer){
1153 clearTimeout(m.autoHideTimer);
1154 delete m.autoHideTimer;
1159 function onBeforeShow(m){
1160 var pm = m.parentMenu;
1161 if(!pm && !m.allowOtherMenus){
1163 }else if(pm && pm.activeChild && active != m){
1164 pm.activeChild.hide();
1169 function onMouseDown(e){
1170 Roo.log("on MouseDown");
1171 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1179 function onBeforeCheck(mi, state){
1181 var g = groups[mi.group];
1182 for(var i = 0, l = g.length; i < l; i++){
1184 g[i].setChecked(false);
1193 * Hides all menus that are currently visible
1195 hideAll : function(){
1200 register : function(menu){
1204 menus[menu.id] = menu;
1205 menu.on("beforehide", onBeforeHide);
1206 menu.on("hide", onHide);
1207 menu.on("beforeshow", onBeforeShow);
1208 menu.on("show", onShow);
1210 if(g && menu.events["checkchange"]){
1214 groups[g].push(menu);
1215 menu.on("checkchange", onCheck);
1220 * Returns a {@link Roo.menu.Menu} object
1221 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1222 * be used to generate and return a new Menu instance.
1224 get : function(menu){
1225 if(typeof menu == "string"){ // menu id
1227 }else if(menu.events){ // menu instance
1230 /*else if(typeof menu.length == 'number'){ // array of menu items?
1231 return new Roo.bootstrap.Menu({items:menu});
1232 }else{ // otherwise, must be a config
1233 return new Roo.bootstrap.Menu(menu);
1240 unregister : function(menu){
1241 delete menus[menu.id];
1242 menu.un("beforehide", onBeforeHide);
1243 menu.un("hide", onHide);
1244 menu.un("beforeshow", onBeforeShow);
1245 menu.un("show", onShow);
1247 if(g && menu.events["checkchange"]){
1248 groups[g].remove(menu);
1249 menu.un("checkchange", onCheck);
1254 registerCheckable : function(menuItem){
1255 var g = menuItem.group;
1260 groups[g].push(menuItem);
1261 menuItem.on("beforecheckchange", onBeforeCheck);
1266 unregisterCheckable : function(menuItem){
1267 var g = menuItem.group;
1269 groups[g].remove(menuItem);
1270 menuItem.un("beforecheckchange", onBeforeCheck);
1282 * @class Roo.bootstrap.Menu
1283 * @extends Roo.bootstrap.Component
1284 * Bootstrap Menu class - container for MenuItems
1285 * @cfg {String} type type of menu
1289 * @param {Object} config The config object
1293 Roo.bootstrap.Menu = function(config){
1294 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1295 if (this.registerMenu) {
1296 Roo.bootstrap.MenuMgr.register(this);
1301 * Fires before this menu is displayed
1302 * @param {Roo.menu.Menu} this
1307 * Fires before this menu is hidden
1308 * @param {Roo.menu.Menu} this
1313 * Fires after this menu is displayed
1314 * @param {Roo.menu.Menu} this
1319 * Fires after this menu is hidden
1320 * @param {Roo.menu.Menu} this
1325 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1326 * @param {Roo.menu.Menu} this
1327 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1328 * @param {Roo.EventObject} e
1333 * Fires when the mouse is hovering over this menu
1334 * @param {Roo.menu.Menu} this
1335 * @param {Roo.EventObject} e
1336 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1341 * Fires when the mouse exits this menu
1342 * @param {Roo.menu.Menu} this
1343 * @param {Roo.EventObject} e
1344 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1349 * Fires when a menu item contained in this menu is clicked
1350 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1351 * @param {Roo.EventObject} e
1355 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1358 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1362 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1365 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1367 registerMenu : true,
1369 menuItems :false, // stores the menu items..
1375 getChildContainer : function() {
1379 getAutoCreate : function(){
1381 //if (['right'].indexOf(this.align)!==-1) {
1382 // cfg.cn[1].cls += ' pull-right'
1386 cls : 'dropdown-menu' ,
1387 style : 'z-index:1000'
1391 if (this.type === 'submenu') {
1392 cfg.cls = 'submenu active'
1397 initEvents : function() {
1399 // Roo.log("ADD event");
1400 // Roo.log(this.triggerEl.dom);
1401 this.triggerEl.on('click', this.onTriggerPress, this);
1402 this.triggerEl.addClass('dropdown-toggle');
1403 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1405 this.el.on("mouseover", this.onMouseOver, this);
1406 this.el.on("mouseout", this.onMouseOut, this);
1410 findTargetItem : function(e){
1411 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1415 //Roo.log(t); Roo.log(t.id);
1417 //Roo.log(this.menuitems);
1418 return this.menuitems.get(t.id);
1420 //return this.items.get(t.menuItemId);
1425 onClick : function(e){
1426 Roo.log("menu.onClick");
1427 var t = this.findTargetItem(e);
1433 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1434 if(t == this.activeItem && t.shouldDeactivate(e)){
1435 this.activeItem.deactivate();
1436 delete this.activeItem;
1440 this.setActiveItem(t, true);
1447 Roo.log('pass click event');
1451 this.fireEvent("click", this, t, e);
1455 onMouseOver : function(e){
1456 var t = this.findTargetItem(e);
1459 // if(t.canActivate && !t.disabled){
1460 // this.setActiveItem(t, true);
1464 this.fireEvent("mouseover", this, e, t);
1466 isVisible : function(){
1467 return !this.hidden;
1469 onMouseOut : function(e){
1470 var t = this.findTargetItem(e);
1473 // if(t == this.activeItem && t.shouldDeactivate(e)){
1474 // this.activeItem.deactivate();
1475 // delete this.activeItem;
1478 this.fireEvent("mouseout", this, e, t);
1483 * Displays this menu relative to another element
1484 * @param {String/HTMLElement/Roo.Element} element The element to align to
1485 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1486 * the element (defaults to this.defaultAlign)
1487 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1489 show : function(el, pos, parentMenu){
1490 this.parentMenu = parentMenu;
1494 this.fireEvent("beforeshow", this);
1495 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1498 * Displays this menu at a specific xy position
1499 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1500 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1502 showAt : function(xy, parentMenu, /* private: */_e){
1503 this.parentMenu = parentMenu;
1508 this.fireEvent("beforeshow", this);
1510 //xy = this.el.adjustForConstraints(xy);
1512 //this.el.setXY(xy);
1514 this.hideMenuItems();
1515 this.hidden = false;
1516 this.triggerEl.addClass('open');
1518 this.fireEvent("show", this);
1524 this.doFocus.defer(50, this);
1528 doFocus : function(){
1530 this.focusEl.focus();
1535 * Hides this menu and optionally all parent menus
1536 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1538 hide : function(deep){
1540 this.hideMenuItems();
1541 if(this.el && this.isVisible()){
1542 this.fireEvent("beforehide", this);
1543 if(this.activeItem){
1544 this.activeItem.deactivate();
1545 this.activeItem = null;
1547 this.triggerEl.removeClass('open');;
1549 this.fireEvent("hide", this);
1551 if(deep === true && this.parentMenu){
1552 this.parentMenu.hide(true);
1556 onTriggerPress : function(e)
1559 Roo.log('trigger press');
1560 //Roo.log(e.getTarget());
1561 // Roo.log(this.triggerEl.dom);
1562 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1565 if (this.isVisible()) {
1569 this.show(this.triggerEl, false, false);
1578 hideMenuItems : function()
1580 //$(backdrop).remove()
1581 Roo.select('.open',true).each(function(aa) {
1583 aa.removeClass('open');
1584 //var parent = getParent($(this))
1585 //var relatedTarget = { relatedTarget: this }
1587 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1588 //if (e.isDefaultPrevented()) return
1589 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1592 addxtypeChild : function (tree, cntr) {
1593 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1595 this.menuitems.add(comp);
1616 * @class Roo.bootstrap.MenuItem
1617 * @extends Roo.bootstrap.Component
1618 * Bootstrap MenuItem class
1619 * @cfg {String} html the menu label
1620 * @cfg {String} href the link
1621 * @cfg {Boolean} preventDefault (true | false) default true
1625 * Create a new MenuItem
1626 * @param {Object} config The config object
1630 Roo.bootstrap.MenuItem = function(config){
1631 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1636 * The raw click event for the entire grid.
1637 * @param {Roo.EventObject} e
1643 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1647 preventDefault: true,
1649 getAutoCreate : function(){
1652 cls: 'dropdown-menu-item',
1662 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1663 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1667 initEvents: function() {
1669 //this.el.select('a').on('click', this.onClick, this);
1672 onClick : function(e)
1674 Roo.log('item on click ');
1675 //if(this.preventDefault){
1676 // e.preventDefault();
1678 //this.parent().hideMenuItems();
1680 this.fireEvent('click', this, e);
1699 * @class Roo.bootstrap.MenuSeparator
1700 * @extends Roo.bootstrap.Component
1701 * Bootstrap MenuSeparator class
1704 * Create a new MenuItem
1705 * @param {Object} config The config object
1709 Roo.bootstrap.MenuSeparator = function(config){
1710 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1713 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1715 getAutoCreate : function(){
1730 <div class="modal fade">
1731 <div class="modal-dialog">
1732 <div class="modal-content">
1733 <div class="modal-header">
1734 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1735 <h4 class="modal-title">Modal title</h4>
1737 <div class="modal-body">
1738 <p>One fine body…</p>
1740 <div class="modal-footer">
1741 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1742 <button type="button" class="btn btn-primary">Save changes</button>
1744 </div><!-- /.modal-content -->
1745 </div><!-- /.modal-dialog -->
1746 </div><!-- /.modal -->
1756 * @class Roo.bootstrap.Modal
1757 * @extends Roo.bootstrap.Component
1758 * Bootstrap Modal class
1759 * @cfg {String} title Title of dialog
1760 * @cfg {Array} buttons Array of buttons or standard button set..
1763 * Create a new Modal Dialog
1764 * @param {Object} config The config object
1767 Roo.bootstrap.Modal = function(config){
1768 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1773 * The raw btnclick event for the button
1774 * @param {Roo.EventObject} e
1778 this.buttons = this.buttons || [];
1781 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1783 title : 'test dialog',
1790 onRender : function(ct, position)
1792 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1795 var cfg = Roo.apply({}, this.getAutoCreate());
1798 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1800 //if (!cfg.name.length) {
1804 cfg.cls += ' ' + this.cls;
1807 cfg.style = this.style;
1809 this.el = Roo.get(document.body).createChild(cfg, position);
1811 //var type = this.el.dom.type;
1813 if(this.tabIndex !== undefined){
1814 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1819 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1820 this.maskEl.enableDisplayMode("block");
1822 //this.el.addClass("x-dlg-modal");
1824 if (this.buttons.length) {
1825 Roo.each(this.buttons, function(bb) {
1826 b = Roo.apply({}, bb);
1827 b.xns = b.xns || Roo.bootstrap;
1828 b.xtype = b.xtype || 'Button';
1829 if (typeof(b.listeners) == 'undefined') {
1830 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1833 var btn = Roo.factory(b);
1835 btn.onRender(this.el.select('.modal-footer').first());
1839 // render the children.
1842 if(typeof(this.items) != 'undefined'){
1843 var items = this.items;
1846 for(var i =0;i < items.length;i++) {
1847 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1851 this.items = nitems;
1853 this.body = this.el.select('.modal-body',true).first();
1854 this.close = this.el.select('.modal-header .close', true).first();
1855 this.footer = this.el.select('.modal-footer',true).first();
1857 //this.el.addClass([this.fieldClass, this.cls]);
1860 getAutoCreate : function(){
1865 html : this.html || ''
1871 style : 'display: none',
1874 cls: "modal-dialog",
1877 cls : "modal-content",
1880 cls : 'modal-header',
1889 cls : 'modal-title',
1897 cls : 'modal-footer'
1913 getChildContainer : function() {
1915 return this.el.select('.modal-body',true).first();
1918 getButtonContainer : function() {
1919 return this.el.select('.modal-footer',true).first();
1922 initEvents : function()
1924 this.el.select('.modal-header .close').on('click', this.hide, this);
1926 // this.addxtype(this);
1930 if (!this.rendered) {
1934 this.el.addClass('on');
1935 this.el.removeClass('fade');
1936 this.el.setStyle('display', 'block');
1937 Roo.get(document.body).addClass("x-body-masked");
1938 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1940 this.el.setStyle('zIndex', '10001');
1941 this.fireEvent('show', this);
1947 Roo.log('Modal hide?!');
1949 Roo.get(document.body).removeClass("x-body-masked");
1950 this.el.removeClass('on');
1951 this.el.addClass('fade');
1952 this.el.setStyle('display', 'none');
1953 this.fireEvent('hide', this);
1956 addButton : function(str, cb)
1960 var b = Roo.apply({}, { html : str } );
1961 b.xns = b.xns || Roo.bootstrap;
1962 b.xtype = b.xtype || 'Button';
1963 if (typeof(b.listeners) == 'undefined') {
1964 b.listeners = { click : cb.createDelegate(this) };
1967 var btn = Roo.factory(b);
1969 btn.onRender(this.el.select('.modal-footer').first());
1975 setDefaultButton : function(btn)
1977 //this.el.select('.modal-footer').()
1979 resizeTo: function(w,h)
1983 setContentSize : function(w, h)
1987 onButtonClick: function(btn,e)
1990 this.fireEvent('btnclick', btn.name, e);
1992 setTitle: function(str) {
1993 this.el.select('.modal-title',true).first().dom.innerHTML = str;
1999 Roo.apply(Roo.bootstrap.Modal, {
2001 * Button config that displays a single OK button
2010 * Button config that displays Yes and No buttons
2026 * Button config that displays OK and Cancel buttons
2041 * Button config that displays Yes, No and Cancel buttons
2063 * messagebox - can be used as a replace
2067 * @class Roo.MessageBox
2068 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2072 Roo.Msg.alert('Status', 'Changes saved successfully.');
2074 // Prompt for user data:
2075 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2077 // process text value...
2081 // Show a dialog using config options:
2083 title:'Save Changes?',
2084 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2085 buttons: Roo.Msg.YESNOCANCEL,
2092 Roo.bootstrap.MessageBox = function(){
2093 var dlg, opt, mask, waitTimer;
2094 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2095 var buttons, activeTextEl, bwidth;
2099 var handleButton = function(button){
2101 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2105 var handleHide = function(){
2107 dlg.el.removeClass(opt.cls);
2110 // Roo.TaskMgr.stop(waitTimer);
2111 // waitTimer = null;
2116 var updateButtons = function(b){
2119 buttons["ok"].hide();
2120 buttons["cancel"].hide();
2121 buttons["yes"].hide();
2122 buttons["no"].hide();
2123 //dlg.footer.dom.style.display = 'none';
2126 dlg.footer.dom.style.display = '';
2127 for(var k in buttons){
2128 if(typeof buttons[k] != "function"){
2131 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2132 width += buttons[k].el.getWidth()+15;
2142 var handleEsc = function(d, k, e){
2143 if(opt && opt.closable !== false){
2153 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2154 * @return {Roo.BasicDialog} The BasicDialog element
2156 getDialog : function(){
2158 dlg = new Roo.bootstrap.Modal( {
2161 //constraintoviewport:false,
2163 //collapsible : false,
2168 //buttonAlign:"center",
2169 closeClick : function(){
2170 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2173 handleButton("cancel");
2178 dlg.on("hide", handleHide);
2180 //dlg.addKeyListener(27, handleEsc);
2182 this.buttons = buttons;
2183 var bt = this.buttonText;
2184 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2185 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2186 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2187 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2189 bodyEl = dlg.body.createChild({
2191 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2192 '<textarea class="roo-mb-textarea"></textarea>' +
2193 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2195 msgEl = bodyEl.dom.firstChild;
2196 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2197 textboxEl.enableDisplayMode();
2198 textboxEl.addKeyListener([10,13], function(){
2199 if(dlg.isVisible() && opt && opt.buttons){
2202 }else if(opt.buttons.yes){
2203 handleButton("yes");
2207 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2208 textareaEl.enableDisplayMode();
2209 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2210 progressEl.enableDisplayMode();
2211 var pf = progressEl.dom.firstChild;
2213 pp = Roo.get(pf.firstChild);
2214 pp.setHeight(pf.offsetHeight);
2222 * Updates the message box body text
2223 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2224 * the XHTML-compliant non-breaking space character '&#160;')
2225 * @return {Roo.MessageBox} This message box
2227 updateText : function(text){
2228 if(!dlg.isVisible() && !opt.width){
2229 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2231 msgEl.innerHTML = text || ' ';
2233 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2234 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2236 Math.min(opt.width || cw , this.maxWidth),
2237 Math.max(opt.minWidth || this.minWidth, bwidth)
2240 activeTextEl.setWidth(w);
2242 if(dlg.isVisible()){
2243 dlg.fixedcenter = false;
2245 // to big, make it scroll. = But as usual stupid IE does not support
2248 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2249 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2250 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2252 bodyEl.dom.style.height = '';
2253 bodyEl.dom.style.overflowY = '';
2256 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2258 bodyEl.dom.style.overflowX = '';
2261 dlg.setContentSize(w, bodyEl.getHeight());
2262 if(dlg.isVisible()){
2263 dlg.fixedcenter = true;
2269 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2270 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2271 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2272 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2273 * @return {Roo.MessageBox} This message box
2275 updateProgress : function(value, text){
2277 this.updateText(text);
2279 if (pp) { // weird bug on my firefox - for some reason this is not defined
2280 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2286 * Returns true if the message box is currently displayed
2287 * @return {Boolean} True if the message box is visible, else false
2289 isVisible : function(){
2290 return dlg && dlg.isVisible();
2294 * Hides the message box if it is displayed
2297 if(this.isVisible()){
2303 * Displays a new message box, or reinitializes an existing message box, based on the config options
2304 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2305 * The following config object properties are supported:
2307 Property Type Description
2308 ---------- --------------- ------------------------------------------------------------------------------------
2309 animEl String/Element An id or Element from which the message box should animate as it opens and
2310 closes (defaults to undefined)
2311 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2312 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2313 closable Boolean False to hide the top-right close button (defaults to true). Note that
2314 progress and wait dialogs will ignore this property and always hide the
2315 close button as they can only be closed programmatically.
2316 cls String A custom CSS class to apply to the message box element
2317 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2318 displayed (defaults to 75)
2319 fn Function A callback function to execute after closing the dialog. The arguments to the
2320 function will be btn (the name of the button that was clicked, if applicable,
2321 e.g. "ok"), and text (the value of the active text field, if applicable).
2322 Progress and wait dialogs will ignore this option since they do not respond to
2323 user actions and can only be closed programmatically, so any required function
2324 should be called by the same code after it closes the dialog.
2325 icon String A CSS class that provides a background image to be used as an icon for
2326 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2327 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2328 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2329 modal Boolean False to allow user interaction with the page while the message box is
2330 displayed (defaults to true)
2331 msg String A string that will replace the existing message box body text (defaults
2332 to the XHTML-compliant non-breaking space character ' ')
2333 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2334 progress Boolean True to display a progress bar (defaults to false)
2335 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2336 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2337 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2338 title String The title text
2339 value String The string value to set into the active textbox element if displayed
2340 wait Boolean True to display a progress bar (defaults to false)
2341 width Number The width of the dialog in pixels
2348 msg: 'Please enter your address:',
2350 buttons: Roo.MessageBox.OKCANCEL,
2353 animEl: 'addAddressBtn'
2356 * @param {Object} config Configuration options
2357 * @return {Roo.MessageBox} This message box
2359 show : function(options)
2362 // this causes nightmares if you show one dialog after another
2363 // especially on callbacks..
2365 if(this.isVisible()){
2368 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2369 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2370 Roo.log("New Dialog Message:" + options.msg )
2371 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2372 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2375 var d = this.getDialog();
2377 d.setTitle(opt.title || " ");
2378 d.close.setDisplayed(opt.closable !== false);
2379 activeTextEl = textboxEl;
2380 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2385 textareaEl.setHeight(typeof opt.multiline == "number" ?
2386 opt.multiline : this.defaultTextHeight);
2387 activeTextEl = textareaEl;
2396 progressEl.setDisplayed(opt.progress === true);
2397 this.updateProgress(0);
2398 activeTextEl.dom.value = opt.value || "";
2400 dlg.setDefaultButton(activeTextEl);
2402 var bs = opt.buttons;
2406 }else if(bs && bs.yes){
2407 db = buttons["yes"];
2409 dlg.setDefaultButton(db);
2411 bwidth = updateButtons(opt.buttons);
2412 this.updateText(opt.msg);
2414 d.el.addClass(opt.cls);
2416 d.proxyDrag = opt.proxyDrag === true;
2417 d.modal = opt.modal !== false;
2418 d.mask = opt.modal !== false ? mask : false;
2420 // force it to the end of the z-index stack so it gets a cursor in FF
2421 document.body.appendChild(dlg.el.dom);
2422 d.animateTarget = null;
2423 d.show(options.animEl);
2429 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2430 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2431 * and closing the message box when the process is complete.
2432 * @param {String} title The title bar text
2433 * @param {String} msg The message box body text
2434 * @return {Roo.MessageBox} This message box
2436 progress : function(title, msg){
2443 minWidth: this.minProgressWidth,
2450 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2451 * If a callback function is passed it will be called after the user clicks the button, and the
2452 * id of the button that was clicked will be passed as the only parameter to the callback
2453 * (could also be the top-right close button).
2454 * @param {String} title The title bar text
2455 * @param {String} msg The message box body text
2456 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2457 * @param {Object} scope (optional) The scope of the callback function
2458 * @return {Roo.MessageBox} This message box
2460 alert : function(title, msg, fn, scope){
2473 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2474 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2475 * You are responsible for closing the message box when the process is complete.
2476 * @param {String} msg The message box body text
2477 * @param {String} title (optional) The title bar text
2478 * @return {Roo.MessageBox} This message box
2480 wait : function(msg, title){
2491 waitTimer = Roo.TaskMgr.start({
2493 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2501 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2502 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2503 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2504 * @param {String} title The title bar text
2505 * @param {String} msg The message box body text
2506 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2507 * @param {Object} scope (optional) The scope of the callback function
2508 * @return {Roo.MessageBox} This message box
2510 confirm : function(title, msg, fn, scope){
2514 buttons: this.YESNO,
2523 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2524 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2525 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2526 * (could also be the top-right close button) and the text that was entered will be passed as the two
2527 * parameters to the callback.
2528 * @param {String} title The title bar text
2529 * @param {String} msg The message box body text
2530 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2531 * @param {Object} scope (optional) The scope of the callback function
2532 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2533 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2534 * @return {Roo.MessageBox} This message box
2536 prompt : function(title, msg, fn, scope, multiline){
2540 buttons: this.OKCANCEL,
2545 multiline: multiline,
2552 * Button config that displays a single OK button
2557 * Button config that displays Yes and No buttons
2560 YESNO : {yes:true, no:true},
2562 * Button config that displays OK and Cancel buttons
2565 OKCANCEL : {ok:true, cancel:true},
2567 * Button config that displays Yes, No and Cancel buttons
2570 YESNOCANCEL : {yes:true, no:true, cancel:true},
2573 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2576 defaultTextHeight : 75,
2578 * The maximum width in pixels of the message box (defaults to 600)
2583 * The minimum width in pixels of the message box (defaults to 100)
2588 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2589 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2592 minProgressWidth : 250,
2594 * An object containing the default button text strings that can be overriden for localized language support.
2595 * Supported properties are: ok, cancel, yes and no.
2596 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2609 * Shorthand for {@link Roo.MessageBox}
2611 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2612 Roo.Msg = Roo.Msg || Roo.MessageBox;
2621 * @class Roo.bootstrap.Navbar
2622 * @extends Roo.bootstrap.Component
2623 * Bootstrap Navbar class
2624 * @cfg {Boolean} sidebar has side bar
2625 * @cfg {Boolean} bar is a bar?
2626 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2627 * @cfg {String} brand what is brand
2628 * @cfg {Boolean} inverse is inverted color
2629 * @cfg {String} type (nav | pills | tabs)
2630 * @cfg {Boolean} arrangement stacked | justified
2631 * @cfg {String} align (left | right) alignment
2632 * @cfg {String} brand_href href of the brand
2633 * @cfg {Boolean} main (true|false) main nav bar? default false
2634 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2638 * Create a new Navbar
2639 * @param {Object} config The config object
2643 Roo.bootstrap.Navbar = function(config){
2644 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2649 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2668 getAutoCreate : function(){
2673 if (this.sidebar === true) {
2681 if (this.bar === true) {
2689 cls: 'navbar-header',
2694 cls: 'navbar-toggle',
2695 'data-toggle': 'collapse',
2700 html: 'Toggle navigation'
2720 cls: 'collapse navbar-collapse'
2725 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2727 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2728 cfg.cls += ' navbar-' + this.position;
2729 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
2732 if (this.brand !== '') {
2735 href: this.brand_href ? this.brand_href : '#',
2736 cls: 'navbar-brand',
2744 cfg.cls += ' main-nav';
2750 } else if (this.bar === false) {
2753 Roo.log('Property \'bar\' in of Navbar must be either true or false')
2763 if (['tabs','pills'].indexOf(this.type)!==-1) {
2764 cfg.cn[0].cls += ' nav-' + this.type
2766 if (this.type!=='nav') {
2767 Roo.log('nav type must be nav/tabs/pills')
2769 cfg.cn[0].cls += ' navbar-nav'
2772 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2773 cfg.cn[0].cls += ' nav-' + this.arrangement;
2776 if (this.align === 'right') {
2777 cfg.cn[0].cls += ' navbar-right';
2780 cfg.cls += ' navbar-inverse';
2788 initEvents :function ()
2790 //Roo.log(this.el.select('.navbar-toggle',true));
2791 this.el.select('.navbar-toggle',true).on('click', function() {
2792 // Roo.log('click');
2793 this.el.select('.navbar-collapse',true).toggleClass('in');
2801 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2803 var size = this.el.getSize();
2804 this.maskEl.setSize(size.width, size.height);
2805 this.maskEl.enableDisplayMode("block");
2814 getChildContainer : function()
2816 if (this.bar === true) {
2817 return this.el.select('.collapse',true).first();
2849 * @class Roo.bootstrap.NavGroup
2850 * @extends Roo.bootstrap.Component
2851 * Bootstrap NavGroup class
2852 * @cfg {String} align left | right
2853 * @cfg {Boolean} inverse false | true
2854 * @cfg {String} type (nav|pills|tab) default nav
2855 * @cfg {String} navId - reference Id for navbar.
2859 * Create a new nav group
2860 * @param {Object} config The config object
2863 Roo.bootstrap.NavGroup = function(config){
2864 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
2866 Roo.bootstrap.NavGroup.register(this);
2870 * Fires when the active item changes
2871 * @param {Roo.bootstrap.NavGroup} this
2872 * @param {Roo.bootstrap.Navbar.Item} item The item selected
2873 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
2880 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
2891 getAutoCreate : function()
2893 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
2900 if (['tabs','pills'].indexOf(this.type)!==-1) {
2901 cfg.cls += ' nav-' + this.type
2903 if (this.type!=='nav') {
2904 Roo.log('nav type must be nav/tabs/pills')
2906 cfg.cls += ' navbar-nav'
2909 if (this.parent().sidebar === true) {
2912 cls: 'dashboard-menu'
2918 if (this.form === true) {
2924 if (this.align === 'right') {
2925 cfg.cls += ' navbar-right';
2927 cfg.cls += ' navbar-left';
2931 if (this.align === 'right') {
2932 cfg.cls += ' navbar-right';
2936 cfg.cls += ' navbar-inverse';
2944 setActiveItem : function(item)
2947 Roo.each(this.navItems, function(v){
2952 v.setActive(false, true);
2959 item.setActive(true, true);
2960 this.fireEvent('changed', this, item, prev);
2966 register : function(item)
2968 this.navItems.push( item);
2969 item.navId = this.navId;
2972 getNavItem: function(tabId)
2975 Roo.each(this.navItems, function(e) {
2976 if (e.tabId == tabId) {
2988 Roo.apply(Roo.bootstrap.NavGroup, {
2992 register : function(navgrp)
2994 this.groups[navgrp.navId] = navgrp;
2997 get: function(navId) {
2998 return this.groups[navId];
3013 * @class Roo.bootstrap.Navbar.Item
3014 * @extends Roo.bootstrap.Component
3015 * Bootstrap Navbar.Button class
3016 * @cfg {String} href link to
3017 * @cfg {String} html content of button
3018 * @cfg {String} badge text inside badge
3019 * @cfg {String} glyphicon name of glyphicon
3020 * @cfg {String} icon name of font awesome icon
3021 * @cfg {Boolean} active Is item active
3022 * @cfg {Boolean} preventDefault (true | false) default false
3023 * @cfg {String} tabId the tab that this item activates.
3026 * Create a new Navbar Button
3027 * @param {Object} config The config object
3029 Roo.bootstrap.Navbar.Item = function(config){
3030 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3035 * The raw click event for the entire grid.
3036 * @param {Roo.EventObject} e
3041 * Fires when the active item active state changes
3042 * @param {Roo.bootstrap.Navbar.Item} this
3043 * @param {boolean} state the new state
3051 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3059 preventDefault : false,
3062 getAutoCreate : function(){
3064 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3066 if (this.parent().parent().sidebar === true) {
3079 cfg.cn[0].html = this.html;
3083 this.cls += ' active';
3087 cfg.cn[0].cls += ' dropdown-toggle';
3088 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3092 cfg.cn[0].tag = 'a',
3093 cfg.cn[0].href = this.href;
3096 if (this.glyphicon) {
3097 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3101 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3113 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3123 if (this.glyphicon) {
3124 if(cfg.html){cfg.html = ' ' + this.html};
3128 cls: 'glyphicon glyphicon-' + this.glyphicon
3133 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3138 cfg.cn[0].html += " <span class='caret'></span>";
3139 //}else if (!this.href) {
3140 // cfg.cn[0].tag='p';
3141 // cfg.cn[0].cls='navbar-text';
3144 cfg.cn[0].href=this.href||'#';
3145 cfg.cn[0].html=this.html;
3148 if (this.badge !== '') {
3151 cfg.cn[0].html + ' ',
3162 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3167 initEvents: function() {
3168 // Roo.log('init events?');
3169 // Roo.log(this.el.dom);
3170 this.el.select('a',true).on('click', this.onClick, this);
3171 // at this point parent should be available..
3172 this.parent().register(this);
3175 onClick : function(e)
3177 if(this.preventDefault){
3181 if(this.fireEvent('click', this, e) === false){
3185 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3186 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3187 this.parent().setActiveItem(this);
3195 isActive: function () {
3198 setActive : function(state, fire)
3200 this.active = state;
3202 this.el.removeClass('active');
3203 } else if (!this.el.hasClass('active')) {
3204 this.el.addClass('active');
3207 this.fireEvent('changed', this, state);
3212 // this should not be here...
3225 * @class Roo.bootstrap.Row
3226 * @extends Roo.bootstrap.Component
3227 * Bootstrap Row class (contains columns...)
3231 * @param {Object} config The config object
3234 Roo.bootstrap.Row = function(config){
3235 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3238 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3240 getAutoCreate : function(){
3259 * @class Roo.bootstrap.Element
3260 * @extends Roo.bootstrap.Component
3261 * Bootstrap Element class
3262 * @cfg {String} html contents of the element
3263 * @cfg {String} tag tag of the element
3264 * @cfg {String} cls class of the element
3267 * Create a new Element
3268 * @param {Object} config The config object
3271 Roo.bootstrap.Element = function(config){
3272 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3275 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3282 getAutoCreate : function(){
3307 * @class Roo.bootstrap.Pagination
3308 * @extends Roo.bootstrap.Component
3309 * Bootstrap Pagination class
3310 * @cfg {String} size xs | sm | md | lg
3311 * @cfg {Boolean} inverse false | true
3314 * Create a new Pagination
3315 * @param {Object} config The config object
3318 Roo.bootstrap.Pagination = function(config){
3319 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3322 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3328 getAutoCreate : function(){
3334 cfg.cls += ' inverse';
3340 cfg.cls += " " + this.cls;
3358 * @class Roo.bootstrap.PaginationItem
3359 * @extends Roo.bootstrap.Component
3360 * Bootstrap PaginationItem class
3361 * @cfg {String} html text
3362 * @cfg {String} href the link
3363 * @cfg {Boolean} preventDefault (true | false) default true
3364 * @cfg {Boolean} active (true | false) default false
3368 * Create a new PaginationItem
3369 * @param {Object} config The config object
3373 Roo.bootstrap.PaginationItem = function(config){
3374 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3379 * The raw click event for the entire grid.
3380 * @param {Roo.EventObject} e
3386 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3390 preventDefault: true,
3394 getAutoCreate : function(){
3400 href : this.href ? this.href : '#',
3401 html : this.html ? this.html : ''
3411 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3417 initEvents: function() {
3419 this.el.on('click', this.onClick, this);
3422 onClick : function(e)
3424 Roo.log('PaginationItem on click ');
3425 if(this.preventDefault){
3429 this.fireEvent('click', this, e);
3445 * @class Roo.bootstrap.Slider
3446 * @extends Roo.bootstrap.Component
3447 * Bootstrap Slider class
3450 * Create a new Slider
3451 * @param {Object} config The config object
3454 Roo.bootstrap.Slider = function(config){
3455 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3458 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3460 getAutoCreate : function(){
3464 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3468 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3486 * @class Roo.bootstrap.Table
3487 * @extends Roo.bootstrap.Component
3488 * Bootstrap Table class
3489 * @cfg {String} cls table class
3490 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3491 * @cfg {String} bgcolor Specifies the background color for a table
3492 * @cfg {Number} border Specifies whether the table cells should have borders or not
3493 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3494 * @cfg {Number} cellspacing Specifies the space between cells
3495 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3496 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3497 * @cfg {String} sortable Specifies that the table should be sortable
3498 * @cfg {String} summary Specifies a summary of the content of a table
3499 * @cfg {Number} width Specifies the width of a table
3501 * @cfg {boolean} striped Should the rows be alternative striped
3502 * @cfg {boolean} bordered Add borders to the table
3503 * @cfg {boolean} hover Add hover highlighting
3504 * @cfg {boolean} condensed Format condensed
3505 * @cfg {boolean} responsive Format condensed
3511 * Create a new Table
3512 * @param {Object} config The config object
3515 Roo.bootstrap.Table = function(config){
3516 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3519 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3520 this.sm = this.selModel;
3521 this.sm.xmodule = this.xmodule || false;
3523 if (this.cm && typeof(this.cm.config) == 'undefined') {
3524 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
3525 this.cm = this.colModel;
3526 this.cm.xmodule = this.xmodule || false;
3529 this.store= Roo.factory(this.store, Roo.data);
3530 this.ds = this.store;
3531 this.ds.xmodule = this.xmodule || false;
3536 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3558 getAutoCreate : function(){
3559 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3568 cfg.cls += ' table-striped';
3571 cfg.cls += ' table-hover';
3573 if (this.bordered) {
3574 cfg.cls += ' table-bordered';
3576 if (this.condensed) {
3577 cfg.cls += ' table-condensed';
3579 if (this.responsive) {
3580 cfg.cls += ' table-responsive';
3587 cfg.cls+= ' ' +this.cls;
3590 // this lot should be simplifed...
3593 cfg.align=this.align;
3596 cfg.bgcolor=this.bgcolor;
3599 cfg.border=this.border;
3601 if (this.cellpadding) {
3602 cfg.cellpadding=this.cellpadding;
3604 if (this.cellspacing) {
3605 cfg.cellspacing=this.cellspacing;
3608 cfg.frame=this.frame;
3611 cfg.rules=this.rules;
3613 if (this.sortable) {
3614 cfg.sortable=this.sortable;
3617 cfg.summary=this.summary;
3620 cfg.width=this.width;
3623 if(this.store || this.cm){
3624 cfg.cn.push(this.renderHeader());
3625 cfg.cn.push(this.renderBody());
3626 cfg.cn.push(this.renderFooter());
3628 cfg.cls+= ' TableGrid';
3634 // initTableGrid : function()
3643 // var cm = this.cm;
3645 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3648 // html: cm.getColumnHeader(i)
3652 // cfg.push(header);
3659 initEvents : function()
3661 if(!this.store || !this.cm){
3665 Roo.log('initEvents with ds!!!!');
3669 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3670 e.on('click', _this.sort, _this);
3672 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
3673 // this.maskEl.enableDisplayMode("block");
3674 // this.maskEl.show();
3676 this.store.on('load', this.onLoad, this);
3677 this.store.on('beforeload', this.onBeforeLoad, this);
3685 sort : function(e,el)
3687 var col = Roo.get(el)
3689 if(!col.hasClass('sortable')){
3693 var sort = col.attr('sort');
3696 if(col.hasClass('glyphicon-arrow-up')){
3700 this.store.sortInfo = {field : sort, direction : dir};
3705 renderHeader : function()
3714 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3716 var config = cm.config[i];
3720 html: cm.getColumnHeader(i)
3723 if(typeof(config.dataIndex) != 'undefined'){
3724 c.sort = config.dataIndex;
3727 if(typeof(config.sortable) != 'undefined' && config.sortable){
3731 if(typeof(config.width) != 'undefined'){
3732 c.style = 'width:' + config.width + 'px';
3741 renderBody : function()
3751 renderFooter : function()
3763 Roo.log('ds onload');
3768 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3769 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
3771 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
3772 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
3775 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
3776 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
3780 var tbody = this.el.select('tbody', true).first();
3784 if(this.store.getCount() > 0){
3785 this.store.data.each(function(d){
3791 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3792 var renderer = cm.getRenderer(i);
3793 var config = cm.config[i];
3797 if(typeof(renderer) !== 'undefined'){
3798 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3801 if(typeof(value) === 'object'){
3811 html: (typeof(value) === 'object') ? '' : value
3814 if(typeof(config.width) != 'undefined'){
3815 td.style = 'width:' + config.width + 'px';
3822 tbody.createChild(row);
3830 Roo.each(renders, function(r){
3831 _this.renderColumn(r);
3835 // if(this.loadMask){
3836 // this.maskEl.hide();
3840 onBeforeLoad : function()
3842 Roo.log('ds onBeforeLoad');
3846 // if(this.loadMask){
3847 // this.maskEl.show();
3853 this.el.select('tbody', true).first().dom.innerHTML = '';
3856 getSelectionModel : function(){
3858 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3860 return this.selModel;
3863 renderColumn : function(r)
3866 r.cfg.render(Roo.get(r.id));
3869 Roo.each(r.cfg.cn, function(c){
3874 _this.renderColumn(child);
3891 * @class Roo.bootstrap.TableCell
3892 * @extends Roo.bootstrap.Component
3893 * Bootstrap TableCell class
3894 * @cfg {String} html cell contain text
3895 * @cfg {String} cls cell class
3896 * @cfg {String} tag cell tag (td|th) default td
3897 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3898 * @cfg {String} align Aligns the content in a cell
3899 * @cfg {String} axis Categorizes cells
3900 * @cfg {String} bgcolor Specifies the background color of a cell
3901 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3902 * @cfg {Number} colspan Specifies the number of columns a cell should span
3903 * @cfg {String} headers Specifies one or more header cells a cell is related to
3904 * @cfg {Number} height Sets the height of a cell
3905 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3906 * @cfg {Number} rowspan Sets the number of rows a cell should span
3907 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3908 * @cfg {String} valign Vertical aligns the content in a cell
3909 * @cfg {Number} width Specifies the width of a cell
3912 * Create a new TableCell
3913 * @param {Object} config The config object
3916 Roo.bootstrap.TableCell = function(config){
3917 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3920 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3940 getAutoCreate : function(){
3941 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3961 cfg.align=this.align
3967 cfg.bgcolor=this.bgcolor
3970 cfg.charoff=this.charoff
3973 cfg.colspan=this.colspan
3976 cfg.headers=this.headers
3979 cfg.height=this.height
3982 cfg.nowrap=this.nowrap
3985 cfg.rowspan=this.rowspan
3988 cfg.scope=this.scope
3991 cfg.valign=this.valign
3994 cfg.width=this.width
4013 * @class Roo.bootstrap.TableRow
4014 * @extends Roo.bootstrap.Component
4015 * Bootstrap TableRow class
4016 * @cfg {String} cls row class
4017 * @cfg {String} align Aligns the content in a table row
4018 * @cfg {String} bgcolor Specifies a background color for a table row
4019 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4020 * @cfg {String} valign Vertical aligns the content in a table row
4023 * Create a new TableRow
4024 * @param {Object} config The config object
4027 Roo.bootstrap.TableRow = function(config){
4028 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4031 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4039 getAutoCreate : function(){
4040 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4050 cfg.align = this.align;
4053 cfg.bgcolor = this.bgcolor;
4056 cfg.charoff = this.charoff;
4059 cfg.valign = this.valign;
4077 * @class Roo.bootstrap.TableBody
4078 * @extends Roo.bootstrap.Component
4079 * Bootstrap TableBody class
4080 * @cfg {String} cls element class
4081 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4082 * @cfg {String} align Aligns the content inside the element
4083 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4084 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4087 * Create a new TableBody
4088 * @param {Object} config The config object
4091 Roo.bootstrap.TableBody = function(config){
4092 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4095 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4103 getAutoCreate : function(){
4104 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4118 cfg.align = this.align;
4121 cfg.charoff = this.charoff;
4124 cfg.valign = this.valign;
4131 // initEvents : function()
4138 // this.store = Roo.factory(this.store, Roo.data);
4139 // this.store.on('load', this.onLoad, this);
4141 // this.store.load();
4145 // onLoad: function ()
4147 // this.fireEvent('load', this);
4157 * Ext JS Library 1.1.1
4158 * Copyright(c) 2006-2007, Ext JS, LLC.
4160 * Originally Released Under LGPL - original licence link has changed is not relivant.
4163 * <script type="text/javascript">
4166 // as we use this in bootstrap.
4167 Roo.namespace('Roo.form');
4169 * @class Roo.form.Action
4170 * Internal Class used to handle form actions
4172 * @param {Roo.form.BasicForm} el The form element or its id
4173 * @param {Object} config Configuration options
4178 // define the action interface
4179 Roo.form.Action = function(form, options){
4181 this.options = options || {};
4184 * Client Validation Failed
4187 Roo.form.Action.CLIENT_INVALID = 'client';
4189 * Server Validation Failed
4192 Roo.form.Action.SERVER_INVALID = 'server';
4194 * Connect to Server Failed
4197 Roo.form.Action.CONNECT_FAILURE = 'connect';
4199 * Reading Data from Server Failed
4202 Roo.form.Action.LOAD_FAILURE = 'load';
4204 Roo.form.Action.prototype = {
4206 failureType : undefined,
4207 response : undefined,
4211 run : function(options){
4216 success : function(response){
4221 handleResponse : function(response){
4225 // default connection failure
4226 failure : function(response){
4228 this.response = response;
4229 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4230 this.form.afterAction(this, false);
4233 processResponse : function(response){
4234 this.response = response;
4235 if(!response.responseText){
4238 this.result = this.handleResponse(response);
4242 // utility functions used internally
4243 getUrl : function(appendParams){
4244 var url = this.options.url || this.form.url || this.form.el.dom.action;
4246 var p = this.getParams();
4248 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4254 getMethod : function(){
4255 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4258 getParams : function(){
4259 var bp = this.form.baseParams;
4260 var p = this.options.params;
4262 if(typeof p == "object"){
4263 p = Roo.urlEncode(Roo.applyIf(p, bp));
4264 }else if(typeof p == 'string' && bp){
4265 p += '&' + Roo.urlEncode(bp);
4268 p = Roo.urlEncode(bp);
4273 createCallback : function(){
4275 success: this.success,
4276 failure: this.failure,
4278 timeout: (this.form.timeout*1000),
4279 upload: this.form.fileUpload ? this.success : undefined
4284 Roo.form.Action.Submit = function(form, options){
4285 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4288 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4291 haveProgress : false,
4292 uploadComplete : false,
4294 // uploadProgress indicator.
4295 uploadProgress : function()
4297 if (!this.form.progressUrl) {
4301 if (!this.haveProgress) {
4302 Roo.MessageBox.progress("Uploading", "Uploading");
4304 if (this.uploadComplete) {
4305 Roo.MessageBox.hide();
4309 this.haveProgress = true;
4311 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4313 var c = new Roo.data.Connection();
4315 url : this.form.progressUrl,
4320 success : function(req){
4321 //console.log(data);
4325 rdata = Roo.decode(req.responseText)
4327 Roo.log("Invalid data from server..");
4331 if (!rdata || !rdata.success) {
4333 Roo.MessageBox.alert(Roo.encode(rdata));
4336 var data = rdata.data;
4338 if (this.uploadComplete) {
4339 Roo.MessageBox.hide();
4344 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4345 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4348 this.uploadProgress.defer(2000,this);
4351 failure: function(data) {
4352 Roo.log('progress url failed ');
4363 // run get Values on the form, so it syncs any secondary forms.
4364 this.form.getValues();
4366 var o = this.options;
4367 var method = this.getMethod();
4368 var isPost = method == 'POST';
4369 if(o.clientValidation === false || this.form.isValid()){
4371 if (this.form.progressUrl) {
4372 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4373 (new Date() * 1) + '' + Math.random());
4378 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4379 form:this.form.el.dom,
4380 url:this.getUrl(!isPost),
4382 params:isPost ? this.getParams() : null,
4383 isUpload: this.form.fileUpload
4386 this.uploadProgress();
4388 }else if (o.clientValidation !== false){ // client validation failed
4389 this.failureType = Roo.form.Action.CLIENT_INVALID;
4390 this.form.afterAction(this, false);
4394 success : function(response)
4396 this.uploadComplete= true;
4397 if (this.haveProgress) {
4398 Roo.MessageBox.hide();
4402 var result = this.processResponse(response);
4403 if(result === true || result.success){
4404 this.form.afterAction(this, true);
4408 this.form.markInvalid(result.errors);
4409 this.failureType = Roo.form.Action.SERVER_INVALID;
4411 this.form.afterAction(this, false);
4413 failure : function(response)
4415 this.uploadComplete= true;
4416 if (this.haveProgress) {
4417 Roo.MessageBox.hide();
4420 this.response = response;
4421 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4422 this.form.afterAction(this, false);
4425 handleResponse : function(response){
4426 if(this.form.errorReader){
4427 var rs = this.form.errorReader.read(response);
4430 for(var i = 0, len = rs.records.length; i < len; i++) {
4431 var r = rs.records[i];
4435 if(errors.length < 1){
4439 success : rs.success,
4445 ret = Roo.decode(response.responseText);
4449 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4459 Roo.form.Action.Load = function(form, options){
4460 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4461 this.reader = this.form.reader;
4464 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4469 Roo.Ajax.request(Roo.apply(
4470 this.createCallback(), {
4471 method:this.getMethod(),
4472 url:this.getUrl(false),
4473 params:this.getParams()
4477 success : function(response){
4479 var result = this.processResponse(response);
4480 if(result === true || !result.success || !result.data){
4481 this.failureType = Roo.form.Action.LOAD_FAILURE;
4482 this.form.afterAction(this, false);
4485 this.form.clearInvalid();
4486 this.form.setValues(result.data);
4487 this.form.afterAction(this, true);
4490 handleResponse : function(response){
4491 if(this.form.reader){
4492 var rs = this.form.reader.read(response);
4493 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4495 success : rs.success,
4499 return Roo.decode(response.responseText);
4503 Roo.form.Action.ACTION_TYPES = {
4504 'load' : Roo.form.Action.Load,
4505 'submit' : Roo.form.Action.Submit
4514 * @class Roo.bootstrap.Form
4515 * @extends Roo.bootstrap.Component
4516 * Bootstrap Form class
4517 * @cfg {String} method GET | POST (default POST)
4518 * @cfg {String} labelAlign top | left (default top)
4519 * @cfg {String} align left | right - for navbars
4524 * @param {Object} config The config object
4528 Roo.bootstrap.Form = function(config){
4529 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4532 * @event clientvalidation
4533 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4534 * @param {Form} this
4535 * @param {Boolean} valid true if the form has passed client-side validation
4537 clientvalidation: true,
4539 * @event beforeaction
4540 * Fires before any action is performed. Return false to cancel the action.
4541 * @param {Form} this
4542 * @param {Action} action The action to be performed
4546 * @event actionfailed
4547 * Fires when an action fails.
4548 * @param {Form} this
4549 * @param {Action} action The action that failed
4551 actionfailed : true,
4553 * @event actioncomplete
4554 * Fires when an action is completed.
4555 * @param {Form} this
4556 * @param {Action} action The action that completed
4558 actioncomplete : true
4563 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4566 * @cfg {String} method
4567 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4572 * The URL to use for form actions if one isn't supplied in the action options.
4575 * @cfg {Boolean} fileUpload
4576 * Set to true if this form is a file upload.
4580 * @cfg {Object} baseParams
4581 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
4585 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
4589 * @cfg {Sting} align (left|right) for navbar forms
4594 activeAction : null,
4597 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4598 * element by passing it or its id or mask the form itself by passing in true.
4601 waitMsgTarget : false,
4606 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4607 * element by passing it or its id or mask the form itself by passing in true.
4611 getAutoCreate : function(){
4615 method : this.method || 'POST',
4616 id : this.id || Roo.id(),
4619 if (this.parent().xtype.match(/^Nav/)) {
4620 cfg.cls = 'navbar-form navbar-' + this.align;
4624 if (this.labelAlign == 'left' ) {
4625 cfg.cls += ' form-horizontal';
4631 initEvents : function()
4633 this.el.on('submit', this.onSubmit, this);
4638 onSubmit : function(e){
4643 * Returns true if client-side validation on the form is successful.
4646 isValid : function(){
4647 var items = this.getItems();
4649 items.each(function(f){
4658 * Returns true if any fields in this form have changed since their original load.
4661 isDirty : function(){
4663 var items = this.getItems();
4664 items.each(function(f){
4674 * Performs a predefined action (submit or load) or custom actions you define on this form.
4675 * @param {String} actionName The name of the action type
4676 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
4677 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
4678 * accept other config options):
4680 Property Type Description
4681 ---------------- --------------- ----------------------------------------------------------------------------------
4682 url String The url for the action (defaults to the form's url)
4683 method String The form method to use (defaults to the form's method, or POST if not defined)
4684 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
4685 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
4686 validate the form on the client (defaults to false)
4688 * @return {BasicForm} this
4690 doAction : function(action, options){
4691 if(typeof action == 'string'){
4692 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
4694 if(this.fireEvent('beforeaction', this, action) !== false){
4695 this.beforeAction(action);
4696 action.run.defer(100, action);
4702 beforeAction : function(action){
4703 var o = action.options;
4705 // not really supported yet.. ??
4707 //if(this.waitMsgTarget === true){
4708 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
4709 //}else if(this.waitMsgTarget){
4710 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
4711 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
4713 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
4719 afterAction : function(action, success){
4720 this.activeAction = null;
4721 var o = action.options;
4723 //if(this.waitMsgTarget === true){
4725 //}else if(this.waitMsgTarget){
4726 // this.waitMsgTarget.unmask();
4728 // Roo.MessageBox.updateProgress(1);
4729 // Roo.MessageBox.hide();
4736 Roo.callback(o.success, o.scope, [this, action]);
4737 this.fireEvent('actioncomplete', this, action);
4741 // failure condition..
4742 // we have a scenario where updates need confirming.
4743 // eg. if a locking scenario exists..
4744 // we look for { errors : { needs_confirm : true }} in the response.
4746 (typeof(action.result) != 'undefined') &&
4747 (typeof(action.result.errors) != 'undefined') &&
4748 (typeof(action.result.errors.needs_confirm) != 'undefined')
4751 Roo.log("not supported yet");
4754 Roo.MessageBox.confirm(
4755 "Change requires confirmation",
4756 action.result.errorMsg,
4761 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
4771 Roo.callback(o.failure, o.scope, [this, action]);
4772 // show an error message if no failed handler is set..
4773 if (!this.hasListener('actionfailed')) {
4774 Roo.log("need to add dialog support");
4776 Roo.MessageBox.alert("Error",
4777 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4778 action.result.errorMsg :
4779 "Saving Failed, please check your entries or try again"
4784 this.fireEvent('actionfailed', this, action);
4789 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4790 * @param {String} id The value to search for
4793 findField : function(id){
4794 var items = this.getItems();
4795 var field = items.get(id);
4797 items.each(function(f){
4798 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4805 return field || null;
4808 * Mark fields in this form invalid in bulk.
4809 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4810 * @return {BasicForm} this
4812 markInvalid : function(errors){
4813 if(errors instanceof Array){
4814 for(var i = 0, len = errors.length; i < len; i++){
4815 var fieldError = errors[i];
4816 var f = this.findField(fieldError.id);
4818 f.markInvalid(fieldError.msg);
4824 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4825 field.markInvalid(errors[id]);
4829 //Roo.each(this.childForms || [], function (f) {
4830 // f.markInvalid(errors);
4837 * Set values for fields in this form in bulk.
4838 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4839 * @return {BasicForm} this
4841 setValues : function(values){
4842 if(values instanceof Array){ // array of objects
4843 for(var i = 0, len = values.length; i < len; i++){
4845 var f = this.findField(v.id);
4847 f.setValue(v.value);
4848 if(this.trackResetOnLoad){
4849 f.originalValue = f.getValue();
4853 }else{ // object hash
4856 if(typeof values[id] != 'function' && (field = this.findField(id))){
4858 if (field.setFromData &&
4860 field.displayField &&
4861 // combos' with local stores can
4862 // be queried via setValue()
4863 // to set their value..
4864 (field.store && !field.store.isLocal)
4868 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4869 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4870 field.setFromData(sd);
4873 field.setValue(values[id]);
4877 if(this.trackResetOnLoad){
4878 field.originalValue = field.getValue();
4884 //Roo.each(this.childForms || [], function (f) {
4885 // f.setValues(values);
4892 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4893 * they are returned as an array.
4894 * @param {Boolean} asString
4897 getValues : function(asString){
4898 //if (this.childForms) {
4899 // copy values from the child forms
4900 // Roo.each(this.childForms, function (f) {
4901 // this.setValues(f.getValues());
4907 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4908 if(asString === true){
4911 return Roo.urlDecode(fs);
4915 * Returns the fields in this form as an object with key/value pairs.
4916 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4919 getFieldValues : function(with_hidden)
4921 var items = this.getItems();
4923 items.each(function(f){
4927 var v = f.getValue();
4928 if (f.inputType =='radio') {
4929 if (typeof(ret[f.getName()]) == 'undefined') {
4930 ret[f.getName()] = ''; // empty..
4933 if (!f.el.dom.checked) {
4941 // not sure if this supported any more..
4942 if ((typeof(v) == 'object') && f.getRawValue) {
4943 v = f.getRawValue() ; // dates..
4945 // combo boxes where name != hiddenName...
4946 if (f.name != f.getName()) {
4947 ret[f.name] = f.getRawValue();
4949 ret[f.getName()] = v;
4956 * Clears all invalid messages in this form.
4957 * @return {BasicForm} this
4959 clearInvalid : function(){
4960 var items = this.getItems();
4962 items.each(function(f){
4973 * @return {BasicForm} this
4976 var items = this.getItems();
4977 items.each(function(f){
4981 Roo.each(this.childForms || [], function (f) {
4988 getItems : function()
4990 var r=new Roo.util.MixedCollection(false, function(o){
4991 return o.id || (o.id = Roo.id());
4993 var iter = function(el) {
5000 Roo.each(el.items,function(e) {
5019 * Ext JS Library 1.1.1
5020 * Copyright(c) 2006-2007, Ext JS, LLC.
5022 * Originally Released Under LGPL - original licence link has changed is not relivant.
5025 * <script type="text/javascript">
5028 * @class Roo.form.VTypes
5029 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5032 Roo.form.VTypes = function(){
5033 // closure these in so they are only created once.
5034 var alpha = /^[a-zA-Z_]+$/;
5035 var alphanum = /^[a-zA-Z0-9_]+$/;
5036 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5037 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5039 // All these messages and functions are configurable
5042 * The function used to validate email addresses
5043 * @param {String} value The email address
5045 'email' : function(v){
5046 return email.test(v);
5049 * The error text to display when the email validation function returns false
5052 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5054 * The keystroke filter mask to be applied on email input
5057 'emailMask' : /[a-z0-9_\.\-@]/i,
5060 * The function used to validate URLs
5061 * @param {String} value The URL
5063 'url' : function(v){
5067 * The error text to display when the url validation function returns false
5070 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5073 * The function used to validate alpha values
5074 * @param {String} value The value
5076 'alpha' : function(v){
5077 return alpha.test(v);
5080 * The error text to display when the alpha validation function returns false
5083 'alphaText' : 'This field should only contain letters and _',
5085 * The keystroke filter mask to be applied on alpha input
5088 'alphaMask' : /[a-z_]/i,
5091 * The function used to validate alphanumeric values
5092 * @param {String} value The value
5094 'alphanum' : function(v){
5095 return alphanum.test(v);
5098 * The error text to display when the alphanumeric validation function returns false
5101 'alphanumText' : 'This field should only contain letters, numbers and _',
5103 * The keystroke filter mask to be applied on alphanumeric input
5106 'alphanumMask' : /[a-z0-9_]/i
5116 * @class Roo.bootstrap.Input
5117 * @extends Roo.bootstrap.Component
5118 * Bootstrap Input class
5119 * @cfg {Boolean} disabled is it disabled
5120 * @cfg {String} fieldLabel - the label associated
5121 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5122 * @cfg {String} name name of the input
5123 * @cfg {string} fieldLabel - the label associated
5124 * @cfg {string} inputType - input / file submit ...
5125 * @cfg {string} placeholder - placeholder to put in text.
5126 * @cfg {string} before - input group add on before
5127 * @cfg {string} after - input group add on after
5128 * @cfg {string} size - (lg|sm) or leave empty..
5129 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5130 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5131 * @cfg {Number} md colspan out of 12 for computer-sized screens
5132 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5133 * @cfg {string} value default value of the input
5134 * @cfg {Number} labelWidth set the width of label (0-12)
5135 * @cfg {String} labelAlign (top|left)
5136 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5140 * Create a new Input
5141 * @param {Object} config The config object
5144 Roo.bootstrap.Input = function(config){
5145 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5150 * Fires when this field receives input focus.
5151 * @param {Roo.form.Field} this
5156 * Fires when this field loses input focus.
5157 * @param {Roo.form.Field} this
5162 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5163 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5164 * @param {Roo.form.Field} this
5165 * @param {Roo.EventObject} e The event object
5170 * Fires just before the field blurs if the field value has changed.
5171 * @param {Roo.form.Field} this
5172 * @param {Mixed} newValue The new value
5173 * @param {Mixed} oldValue The original value
5178 * Fires after the field has been marked as invalid.
5179 * @param {Roo.form.Field} this
5180 * @param {String} msg The validation message
5185 * Fires after the field has been validated with no errors.
5186 * @param {Roo.form.Field} this
5191 * Fires after the key up
5192 * @param {Roo.form.Field} this
5193 * @param {Roo.EventObject} e The event Object
5199 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5201 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5202 automatic validation (defaults to "keyup").
5204 validationEvent : "keyup",
5206 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5208 validateOnBlur : true,
5210 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5212 validationDelay : 250,
5214 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5216 focusClass : "x-form-focus", // not needed???
5220 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5222 invalidClass : "has-error",
5225 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5227 selectOnFocus : false,
5230 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5234 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5239 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5241 disableKeyFilter : false,
5244 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5248 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5252 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5254 blankText : "This field is required",
5257 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5261 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5263 maxLength : Number.MAX_VALUE,
5265 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5267 minLengthText : "The minimum length for this field is {0}",
5269 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5271 maxLengthText : "The maximum length for this field is {0}",
5275 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5276 * If available, this function will be called only after the basic validators all return true, and will be passed the
5277 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5281 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5282 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5283 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5287 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5310 parentLabelAlign : function()
5313 while (parent.parent()) {
5314 parent = parent.parent();
5315 if (typeof(parent.labelAlign) !='undefined') {
5316 return parent.labelAlign;
5323 getAutoCreate : function(){
5325 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5331 if(this.inputType != 'hidden'){
5332 cfg.cls = 'form-group' //input-group
5338 type : this.inputType,
5340 cls : 'form-control',
5341 placeholder : this.placeholder || ''
5345 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5346 input.maxLength = this.maxLength;
5349 if (this.disabled) {
5350 input.disabled=true;
5353 if (this.readOnly) {
5354 input.readonly=true;
5358 input.name = this.name;
5361 input.cls += ' input-' + this.size;
5364 ['xs','sm','md','lg'].map(function(size){
5365 if (settings[size]) {
5366 cfg.cls += ' col-' + size + '-' + settings[size];
5370 var inputblock = input;
5372 if (this.before || this.after) {
5375 cls : 'input-group',
5379 inputblock.cn.push({
5381 cls : 'input-group-addon',
5385 inputblock.cn.push(input);
5387 inputblock.cn.push({
5389 cls : 'input-group-addon',
5396 if (align ==='left' && this.fieldLabel.length) {
5397 Roo.log("left and has label");
5403 cls : 'control-label col-sm-' + this.labelWidth,
5404 html : this.fieldLabel
5408 cls : "col-sm-" + (12 - this.labelWidth),
5415 } else if ( this.fieldLabel.length) {
5421 //cls : 'input-group-addon',
5422 html : this.fieldLabel
5432 Roo.log(" no label && no align");
5441 Roo.log('input-parentType: ' + this.parentType);
5443 if (this.parentType === 'Navbar' && this.parent().bar) {
5444 cfg.cls += ' navbar-form';
5452 * return the real input element.
5454 inputEl: function ()
5456 return this.el.select('input.form-control',true).first();
5458 setDisabled : function(v)
5460 var i = this.inputEl().dom;
5462 i.removeAttribute('disabled');
5466 i.setAttribute('disabled','true');
5468 initEvents : function()
5471 this.inputEl().on("keydown" , this.fireKey, this);
5472 this.inputEl().on("focus", this.onFocus, this);
5473 this.inputEl().on("blur", this.onBlur, this);
5475 this.inputEl().relayEvent('keyup', this);
5477 // reference to original value for reset
5478 this.originalValue = this.getValue();
5479 //Roo.form.TextField.superclass.initEvents.call(this);
5480 if(this.validationEvent == 'keyup'){
5481 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5482 this.inputEl().on('keyup', this.filterValidation, this);
5484 else if(this.validationEvent !== false){
5485 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5488 if(this.selectOnFocus){
5489 this.on("focus", this.preFocus, this);
5492 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5493 this.inputEl().on("keypress", this.filterKeys, this);
5496 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5497 this.el.on("click", this.autoSize, this);
5500 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5501 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5505 filterValidation : function(e){
5506 if(!e.isNavKeyPress()){
5507 this.validationTask.delay(this.validationDelay);
5511 * Validates the field value
5512 * @return {Boolean} True if the value is valid, else false
5514 validate : function(){
5515 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5516 if(this.disabled || this.validateValue(this.getRawValue())){
5517 this.clearInvalid();
5525 * Validates a value according to the field's validation rules and marks the field as invalid
5526 * if the validation fails
5527 * @param {Mixed} value The value to validate
5528 * @return {Boolean} True if the value is valid, else false
5530 validateValue : function(value){
5531 if(value.length < 1) { // if it's blank
5532 if(this.allowBlank){
5533 this.clearInvalid();
5536 this.markInvalid(this.blankText);
5540 if(value.length < this.minLength){
5541 this.markInvalid(String.format(this.minLengthText, this.minLength));
5544 if(value.length > this.maxLength){
5545 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5549 var vt = Roo.form.VTypes;
5550 if(!vt[this.vtype](value, this)){
5551 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5555 if(typeof this.validator == "function"){
5556 var msg = this.validator(value);
5558 this.markInvalid(msg);
5562 if(this.regex && !this.regex.test(value)){
5563 this.markInvalid(this.regexText);
5572 fireKey : function(e){
5573 //Roo.log('field ' + e.getKey());
5574 if(e.isNavKeyPress()){
5575 this.fireEvent("specialkey", this, e);
5578 focus : function (selectText){
5580 this.inputEl().focus();
5581 if(selectText === true){
5582 this.inputEl().dom.select();
5588 onFocus : function(){
5589 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5590 // this.el.addClass(this.focusClass);
5593 this.hasFocus = true;
5594 this.startValue = this.getValue();
5595 this.fireEvent("focus", this);
5599 beforeBlur : Roo.emptyFn,
5603 onBlur : function(){
5605 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5606 //this.el.removeClass(this.focusClass);
5608 this.hasFocus = false;
5609 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
5612 var v = this.getValue();
5613 if(String(v) !== String(this.startValue)){
5614 this.fireEvent('change', this, v, this.startValue);
5616 this.fireEvent("blur", this);
5620 * Resets the current field value to the originally loaded value and clears any validation messages
5623 this.setValue(this.originalValue);
5624 this.clearInvalid();
5627 * Returns the name of the field
5628 * @return {Mixed} name The name field
5630 getName: function(){
5634 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
5635 * @return {Mixed} value The field value
5637 getValue : function(){
5638 return this.inputEl().getValue();
5641 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
5642 * @return {Mixed} value The field value
5644 getRawValue : function(){
5645 var v = this.inputEl().getValue();
5651 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
5652 * @param {Mixed} value The value to set
5654 setRawValue : function(v){
5655 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5658 selectText : function(start, end){
5659 var v = this.getRawValue();
5661 start = start === undefined ? 0 : start;
5662 end = end === undefined ? v.length : end;
5663 var d = this.inputEl().dom;
5664 if(d.setSelectionRange){
5665 d.setSelectionRange(start, end);
5666 }else if(d.createTextRange){
5667 var range = d.createTextRange();
5668 range.moveStart("character", start);
5669 range.moveEnd("character", v.length-end);
5676 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
5677 * @param {Mixed} value The value to set
5679 setValue : function(v){
5682 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5688 processValue : function(value){
5689 if(this.stripCharsRe){
5690 var newValue = value.replace(this.stripCharsRe, '');
5691 if(newValue !== value){
5692 this.setRawValue(newValue);
5699 preFocus : function(){
5701 if(this.selectOnFocus){
5702 this.inputEl().dom.select();
5705 filterKeys : function(e){
5707 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
5710 var c = e.getCharCode(), cc = String.fromCharCode(c);
5711 if(Roo.isIE && (e.isSpecialKey() || !cc)){
5714 if(!this.maskRe.test(cc)){
5719 * Clear any invalid styles/messages for this field
5721 clearInvalid : function(){
5723 if(!this.el || this.preventMark){ // not rendered
5726 this.el.removeClass(this.invalidClass);
5728 switch(this.msgTarget){
5730 this.el.dom.qtip = '';
5733 this.el.dom.title = '';
5737 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5742 this.errorIcon.dom.qtip = '';
5743 this.errorIcon.hide();
5744 this.un('resize', this.alignErrorIcon, this);
5748 var t = Roo.getDom(this.msgTarget);
5750 t.style.display = 'none';
5754 this.fireEvent('valid', this);
5757 * Mark this field as invalid
5758 * @param {String} msg The validation message
5760 markInvalid : function(msg){
5761 if(!this.el || this.preventMark){ // not rendered
5764 this.el.addClass(this.invalidClass);
5766 msg = msg || this.invalidText;
5767 switch(this.msgTarget){
5769 this.el.dom.qtip = msg;
5770 this.el.dom.qclass = 'x-form-invalid-tip';
5771 if(Roo.QuickTips){ // fix for floating editors interacting with DND
5772 Roo.QuickTips.enable();
5776 this.el.dom.title = msg;
5780 var elp = this.el.findParent('.x-form-element', 5, true);
5781 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5782 this.errorEl.setWidth(elp.getWidth(true)-20);
5784 this.errorEl.update(msg);
5785 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5788 if(!this.errorIcon){
5789 var elp = this.el.findParent('.x-form-element', 5, true);
5790 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5792 this.alignErrorIcon();
5793 this.errorIcon.dom.qtip = msg;
5794 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5795 this.errorIcon.show();
5796 this.on('resize', this.alignErrorIcon, this);
5799 var t = Roo.getDom(this.msgTarget);
5801 t.style.display = this.msgDisplay;
5805 this.fireEvent('invalid', this, msg);
5808 SafariOnKeyDown : function(event)
5810 // this is a workaround for a password hang bug on chrome/ webkit.
5812 var isSelectAll = false;
5814 if(this.inputEl().dom.selectionEnd > 0){
5815 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5817 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5818 event.preventDefault();
5823 if(isSelectAll){ // backspace and delete key
5825 event.preventDefault();
5826 // this is very hacky as keydown always get's upper case.
5828 var cc = String.fromCharCode(event.getCharCode());
5829 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
5833 adjustWidth : function(tag, w){
5834 tag = tag.toLowerCase();
5835 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
5836 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5840 if(tag == 'textarea'){
5843 }else if(Roo.isOpera){
5847 if(tag == 'textarea'){
5866 * @class Roo.bootstrap.TextArea
5867 * @extends Roo.bootstrap.Input
5868 * Bootstrap TextArea class
5869 * @cfg {Number} cols Specifies the visible width of a text area
5870 * @cfg {Number} rows Specifies the visible number of lines in a text area
5871 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5872 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5873 * @cfg {string} html text
5876 * Create a new TextArea
5877 * @param {Object} config The config object
5880 Roo.bootstrap.TextArea = function(config){
5881 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5885 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5895 getAutoCreate : function(){
5897 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5908 value : this.value || '',
5909 html: this.html || '',
5910 cls : 'form-control',
5911 placeholder : this.placeholder || ''
5915 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5916 input.maxLength = this.maxLength;
5920 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5924 input.cols = this.cols;
5927 if (this.readOnly) {
5928 input.readonly = true;
5932 input.name = this.name;
5936 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5940 ['xs','sm','md','lg'].map(function(size){
5941 if (settings[size]) {
5942 cfg.cls += ' col-' + size + '-' + settings[size];
5946 var inputblock = input;
5948 if (this.before || this.after) {
5951 cls : 'input-group',
5955 inputblock.cn.push({
5957 cls : 'input-group-addon',
5961 inputblock.cn.push(input);
5963 inputblock.cn.push({
5965 cls : 'input-group-addon',
5972 if (align ==='left' && this.fieldLabel.length) {
5973 Roo.log("left and has label");
5979 cls : 'control-label col-sm-' + this.labelWidth,
5980 html : this.fieldLabel
5984 cls : "col-sm-" + (12 - this.labelWidth),
5991 } else if ( this.fieldLabel.length) {
5997 //cls : 'input-group-addon',
5998 html : this.fieldLabel
6008 Roo.log(" no label && no align");
6018 if (this.disabled) {
6019 input.disabled=true;
6026 * return the real textarea element.
6028 inputEl: function ()
6030 return this.el.select('textarea.form-control',true).first();
6038 * trigger field - base class for combo..
6043 * @class Roo.bootstrap.TriggerField
6044 * @extends Roo.bootstrap.Input
6045 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6046 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6047 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6048 * for which you can provide a custom implementation. For example:
6050 var trigger = new Roo.bootstrap.TriggerField();
6051 trigger.onTriggerClick = myTriggerFn;
6052 trigger.applyTo('my-field');
6055 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6056 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6057 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6058 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6060 * Create a new TriggerField.
6061 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6062 * to the base TextField)
6064 Roo.bootstrap.TriggerField = function(config){
6065 this.mimicing = false;
6066 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6069 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6071 * @cfg {String} triggerClass A CSS class to apply to the trigger
6074 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6078 /** @cfg {Boolean} grow @hide */
6079 /** @cfg {Number} growMin @hide */
6080 /** @cfg {Number} growMax @hide */
6086 autoSize: Roo.emptyFn,
6093 actionMode : 'wrap',
6097 getAutoCreate : function(){
6099 var parent = this.parent();
6101 var align = this.parentLabelAlign();
6106 cls: 'form-group' //input-group
6113 type : this.inputType,
6114 cls : 'form-control',
6115 autocomplete: 'off',
6116 placeholder : this.placeholder || ''
6120 input.name = this.name;
6123 input.cls += ' input-' + this.size;
6126 if (this.disabled) {
6127 input.disabled=true;
6130 var inputblock = input;
6132 if (this.before || this.after) {
6135 cls : 'input-group',
6139 inputblock.cn.push({
6141 cls : 'input-group-addon',
6145 inputblock.cn.push(input);
6147 inputblock.cn.push({
6149 cls : 'input-group-addon',
6162 cls: 'form-hidden-field'
6170 Roo.log('multiple');
6178 cls: 'form-hidden-field'
6182 cls: 'select2-choices',
6186 cls: 'select2-search-field',
6199 cls: 'select2-container input-group',
6204 cls: 'typeahead typeahead-long dropdown-menu',
6205 style: 'display:none'
6213 cls : 'input-group-addon btn dropdown-toggle',
6221 cls: 'combobox-clear',
6235 combobox.cls += ' select2-container-multi';
6238 if (align ==='left' && this.fieldLabel.length) {
6240 Roo.log("left and has label");
6246 cls : 'control-label col-sm-' + this.labelWidth,
6247 html : this.fieldLabel
6251 cls : "col-sm-" + (12 - this.labelWidth),
6258 } else if ( this.fieldLabel.length) {
6264 //cls : 'input-group-addon',
6265 html : this.fieldLabel
6275 Roo.log(" no label && no align");
6282 ['xs','sm','md','lg'].map(function(size){
6283 if (settings[size]) {
6284 cfg.cls += ' col-' + size + '-' + settings[size];
6295 onResize : function(w, h){
6296 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6297 // if(typeof w == 'number'){
6298 // var x = w - this.trigger.getWidth();
6299 // this.inputEl().setWidth(this.adjustWidth('input', x));
6300 // this.trigger.setStyle('left', x+'px');
6305 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6308 getResizeEl : function(){
6309 return this.inputEl();
6313 getPositionEl : function(){
6314 return this.inputEl();
6318 alignErrorIcon : function(){
6319 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6323 initEvents : function(){
6325 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6326 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6328 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6329 if(this.hideTrigger){
6330 this.trigger.setDisplayed(false);
6332 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6336 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6339 //this.trigger.addClassOnOver('x-form-trigger-over');
6340 //this.trigger.addClassOnClick('x-form-trigger-click');
6343 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6348 initTrigger : function(){
6353 onDestroy : function(){
6355 this.trigger.removeAllListeners();
6356 // this.trigger.remove();
6359 // this.wrap.remove();
6361 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6365 onFocus : function(){
6366 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6369 this.wrap.addClass('x-trigger-wrap-focus');
6370 this.mimicing = true;
6371 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6372 if(this.monitorTab){
6373 this.el.on("keydown", this.checkTab, this);
6380 checkTab : function(e){
6381 if(e.getKey() == e.TAB){
6387 onBlur : function(){
6392 mimicBlur : function(e, t){
6394 if(!this.wrap.contains(t) && this.validateBlur()){
6401 triggerBlur : function(){
6402 this.mimicing = false;
6403 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6404 if(this.monitorTab){
6405 this.el.un("keydown", this.checkTab, this);
6407 //this.wrap.removeClass('x-trigger-wrap-focus');
6408 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6412 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6413 validateBlur : function(e, t){
6418 onDisable : function(){
6419 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6421 // this.wrap.addClass('x-item-disabled');
6426 onEnable : function(){
6427 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6429 // this.el.removeClass('x-item-disabled');
6434 onShow : function(){
6435 var ae = this.getActionEl();
6438 ae.dom.style.display = '';
6439 ae.dom.style.visibility = 'visible';
6445 onHide : function(){
6446 var ae = this.getActionEl();
6447 ae.dom.style.display = 'none';
6451 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6452 * by an implementing function.
6454 * @param {EventObject} e
6456 onTriggerClick : Roo.emptyFn
6460 * Ext JS Library 1.1.1
6461 * Copyright(c) 2006-2007, Ext JS, LLC.
6463 * Originally Released Under LGPL - original licence link has changed is not relivant.
6466 * <script type="text/javascript">
6471 * @class Roo.data.SortTypes
6473 * Defines the default sorting (casting?) comparison functions used when sorting data.
6475 Roo.data.SortTypes = {
6477 * Default sort that does nothing
6478 * @param {Mixed} s The value being converted
6479 * @return {Mixed} The comparison value
6486 * The regular expression used to strip tags
6490 stripTagsRE : /<\/?[^>]+>/gi,
6493 * Strips all HTML tags to sort on text only
6494 * @param {Mixed} s The value being converted
6495 * @return {String} The comparison value
6497 asText : function(s){
6498 return String(s).replace(this.stripTagsRE, "");
6502 * Strips all HTML tags to sort on text only - Case insensitive
6503 * @param {Mixed} s The value being converted
6504 * @return {String} The comparison value
6506 asUCText : function(s){
6507 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6511 * Case insensitive string
6512 * @param {Mixed} s The value being converted
6513 * @return {String} The comparison value
6515 asUCString : function(s) {
6516 return String(s).toUpperCase();
6521 * @param {Mixed} s The value being converted
6522 * @return {Number} The comparison value
6524 asDate : function(s) {
6528 if(s instanceof Date){
6531 return Date.parse(String(s));
6536 * @param {Mixed} s The value being converted
6537 * @return {Float} The comparison value
6539 asFloat : function(s) {
6540 var val = parseFloat(String(s).replace(/,/g, ""));
6541 if(isNaN(val)) val = 0;
6547 * @param {Mixed} s The value being converted
6548 * @return {Number} The comparison value
6550 asInt : function(s) {
6551 var val = parseInt(String(s).replace(/,/g, ""));
6552 if(isNaN(val)) val = 0;
6557 * Ext JS Library 1.1.1
6558 * Copyright(c) 2006-2007, Ext JS, LLC.
6560 * Originally Released Under LGPL - original licence link has changed is not relivant.
6563 * <script type="text/javascript">
6567 * @class Roo.data.Record
6568 * Instances of this class encapsulate both record <em>definition</em> information, and record
6569 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
6570 * to access Records cached in an {@link Roo.data.Store} object.<br>
6572 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
6573 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
6576 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
6578 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
6579 * {@link #create}. The parameters are the same.
6580 * @param {Array} data An associative Array of data values keyed by the field name.
6581 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
6582 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
6583 * not specified an integer id is generated.
6585 Roo.data.Record = function(data, id){
6586 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
6591 * Generate a constructor for a specific record layout.
6592 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
6593 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
6594 * Each field definition object may contain the following properties: <ul>
6595 * <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,
6596 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
6597 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
6598 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
6599 * is being used, then this is a string containing the javascript expression to reference the data relative to
6600 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
6601 * to the data item relative to the record element. If the mapping expression is the same as the field name,
6602 * this may be omitted.</p></li>
6603 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
6604 * <ul><li>auto (Default, implies no conversion)</li>
6609 * <li>date</li></ul></p></li>
6610 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
6611 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
6612 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
6613 * by the Reader into an object that will be stored in the Record. It is passed the
6614 * following parameters:<ul>
6615 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
6617 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
6619 * <br>usage:<br><pre><code>
6620 var TopicRecord = Roo.data.Record.create(
6621 {name: 'title', mapping: 'topic_title'},
6622 {name: 'author', mapping: 'username'},
6623 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
6624 {name: 'lastPost', mapping: 'post_time', type: 'date'},
6625 {name: 'lastPoster', mapping: 'user2'},
6626 {name: 'excerpt', mapping: 'post_text'}
6629 var myNewRecord = new TopicRecord({
6630 title: 'Do my job please',
6633 lastPost: new Date(),
6634 lastPoster: 'Animal',
6635 excerpt: 'No way dude!'
6637 myStore.add(myNewRecord);
6642 Roo.data.Record.create = function(o){
6644 f.superclass.constructor.apply(this, arguments);
6646 Roo.extend(f, Roo.data.Record);
6647 var p = f.prototype;
6648 p.fields = new Roo.util.MixedCollection(false, function(field){
6651 for(var i = 0, len = o.length; i < len; i++){
6652 p.fields.add(new Roo.data.Field(o[i]));
6654 f.getField = function(name){
6655 return p.fields.get(name);
6660 Roo.data.Record.AUTO_ID = 1000;
6661 Roo.data.Record.EDIT = 'edit';
6662 Roo.data.Record.REJECT = 'reject';
6663 Roo.data.Record.COMMIT = 'commit';
6665 Roo.data.Record.prototype = {
6667 * Readonly flag - true if this record has been modified.
6676 join : function(store){
6681 * Set the named field to the specified value.
6682 * @param {String} name The name of the field to set.
6683 * @param {Object} value The value to set the field to.
6685 set : function(name, value){
6686 if(this.data[name] == value){
6693 if(typeof this.modified[name] == 'undefined'){
6694 this.modified[name] = this.data[name];
6696 this.data[name] = value;
6697 if(!this.editing && this.store){
6698 this.store.afterEdit(this);
6703 * Get the value of the named field.
6704 * @param {String} name The name of the field to get the value of.
6705 * @return {Object} The value of the field.
6707 get : function(name){
6708 return this.data[name];
6712 beginEdit : function(){
6713 this.editing = true;
6718 cancelEdit : function(){
6719 this.editing = false;
6720 delete this.modified;
6724 endEdit : function(){
6725 this.editing = false;
6726 if(this.dirty && this.store){
6727 this.store.afterEdit(this);
6732 * Usually called by the {@link Roo.data.Store} which owns the Record.
6733 * Rejects all changes made to the Record since either creation, or the last commit operation.
6734 * Modified fields are reverted to their original values.
6736 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6737 * of reject operations.
6739 reject : function(){
6740 var m = this.modified;
6742 if(typeof m[n] != "function"){
6743 this.data[n] = m[n];
6747 delete this.modified;
6748 this.editing = false;
6750 this.store.afterReject(this);
6755 * Usually called by the {@link Roo.data.Store} which owns the Record.
6756 * Commits all changes made to the Record since either creation, or the last commit operation.
6758 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6759 * of commit operations.
6761 commit : function(){
6763 delete this.modified;
6764 this.editing = false;
6766 this.store.afterCommit(this);
6771 hasError : function(){
6772 return this.error != null;
6776 clearError : function(){
6781 * Creates a copy of this record.
6782 * @param {String} id (optional) A new record id if you don't want to use this record's id
6785 copy : function(newId) {
6786 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6790 * Ext JS Library 1.1.1
6791 * Copyright(c) 2006-2007, Ext JS, LLC.
6793 * Originally Released Under LGPL - original licence link has changed is not relivant.
6796 * <script type="text/javascript">
6802 * @class Roo.data.Store
6803 * @extends Roo.util.Observable
6804 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6805 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6807 * 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
6808 * has no knowledge of the format of the data returned by the Proxy.<br>
6810 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6811 * instances from the data object. These records are cached and made available through accessor functions.
6813 * Creates a new Store.
6814 * @param {Object} config A config object containing the objects needed for the Store to access data,
6815 * and read the data into Records.
6817 Roo.data.Store = function(config){
6818 this.data = new Roo.util.MixedCollection(false);
6819 this.data.getKey = function(o){
6822 this.baseParams = {};
6829 "multisort" : "_multisort"
6832 if(config && config.data){
6833 this.inlineData = config.data;
6837 Roo.apply(this, config);
6839 if(this.reader){ // reader passed
6840 this.reader = Roo.factory(this.reader, Roo.data);
6841 this.reader.xmodule = this.xmodule || false;
6842 if(!this.recordType){
6843 this.recordType = this.reader.recordType;
6845 if(this.reader.onMetaChange){
6846 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6850 if(this.recordType){
6851 this.fields = this.recordType.prototype.fields;
6857 * @event datachanged
6858 * Fires when the data cache has changed, and a widget which is using this Store
6859 * as a Record cache should refresh its view.
6860 * @param {Store} this
6865 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6866 * @param {Store} this
6867 * @param {Object} meta The JSON metadata
6872 * Fires when Records have been added to the Store
6873 * @param {Store} this
6874 * @param {Roo.data.Record[]} records The array of Records added
6875 * @param {Number} index The index at which the record(s) were added
6880 * Fires when a Record has been removed from the Store
6881 * @param {Store} this
6882 * @param {Roo.data.Record} record The Record that was removed
6883 * @param {Number} index The index at which the record was removed
6888 * Fires when a Record has been updated
6889 * @param {Store} this
6890 * @param {Roo.data.Record} record The Record that was updated
6891 * @param {String} operation The update operation being performed. Value may be one of:
6893 Roo.data.Record.EDIT
6894 Roo.data.Record.REJECT
6895 Roo.data.Record.COMMIT
6901 * Fires when the data cache has been cleared.
6902 * @param {Store} this
6907 * Fires before a request is made for a new data object. If the beforeload handler returns false
6908 * the load action will be canceled.
6909 * @param {Store} this
6910 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6914 * @event beforeloadadd
6915 * Fires after a new set of Records has been loaded.
6916 * @param {Store} this
6917 * @param {Roo.data.Record[]} records The Records that were loaded
6918 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6920 beforeloadadd : true,
6923 * Fires after a new set of Records has been loaded, before they are added to the store.
6924 * @param {Store} this
6925 * @param {Roo.data.Record[]} records The Records that were loaded
6926 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6927 * @params {Object} return from reader
6931 * @event loadexception
6932 * Fires if an exception occurs in the Proxy during loading.
6933 * Called with the signature of the Proxy's "loadexception" event.
6934 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6937 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6938 * @param {Object} load options
6939 * @param {Object} jsonData from your request (normally this contains the Exception)
6941 loadexception : true
6945 this.proxy = Roo.factory(this.proxy, Roo.data);
6946 this.proxy.xmodule = this.xmodule || false;
6947 this.relayEvents(this.proxy, ["loadexception"]);
6949 this.sortToggle = {};
6950 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6952 Roo.data.Store.superclass.constructor.call(this);
6954 if(this.inlineData){
6955 this.loadData(this.inlineData);
6956 delete this.inlineData;
6960 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6962 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6963 * without a remote query - used by combo/forms at present.
6967 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6970 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6973 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6974 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6977 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6978 * on any HTTP request
6981 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6984 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6988 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6989 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
6994 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
6995 * loaded or when a record is removed. (defaults to false).
6997 pruneModifiedRecords : false,
7003 * Add Records to the Store and fires the add event.
7004 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7006 add : function(records){
7007 records = [].concat(records);
7008 for(var i = 0, len = records.length; i < len; i++){
7009 records[i].join(this);
7011 var index = this.data.length;
7012 this.data.addAll(records);
7013 this.fireEvent("add", this, records, index);
7017 * Remove a Record from the Store and fires the remove event.
7018 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7020 remove : function(record){
7021 var index = this.data.indexOf(record);
7022 this.data.removeAt(index);
7023 if(this.pruneModifiedRecords){
7024 this.modified.remove(record);
7026 this.fireEvent("remove", this, record, index);
7030 * Remove all Records from the Store and fires the clear event.
7032 removeAll : function(){
7034 if(this.pruneModifiedRecords){
7037 this.fireEvent("clear", this);
7041 * Inserts Records to the Store at the given index and fires the add event.
7042 * @param {Number} index The start index at which to insert the passed Records.
7043 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7045 insert : function(index, records){
7046 records = [].concat(records);
7047 for(var i = 0, len = records.length; i < len; i++){
7048 this.data.insert(index, records[i]);
7049 records[i].join(this);
7051 this.fireEvent("add", this, records, index);
7055 * Get the index within the cache of the passed Record.
7056 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7057 * @return {Number} The index of the passed Record. Returns -1 if not found.
7059 indexOf : function(record){
7060 return this.data.indexOf(record);
7064 * Get the index within the cache of the Record with the passed id.
7065 * @param {String} id The id of the Record to find.
7066 * @return {Number} The index of the Record. Returns -1 if not found.
7068 indexOfId : function(id){
7069 return this.data.indexOfKey(id);
7073 * Get the Record with the specified id.
7074 * @param {String} id The id of the Record to find.
7075 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7077 getById : function(id){
7078 return this.data.key(id);
7082 * Get the Record at the specified index.
7083 * @param {Number} index The index of the Record to find.
7084 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7086 getAt : function(index){
7087 return this.data.itemAt(index);
7091 * Returns a range of Records between specified indices.
7092 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7093 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7094 * @return {Roo.data.Record[]} An array of Records
7096 getRange : function(start, end){
7097 return this.data.getRange(start, end);
7101 storeOptions : function(o){
7102 o = Roo.apply({}, o);
7105 this.lastOptions = o;
7109 * Loads the Record cache from the configured Proxy using the configured Reader.
7111 * If using remote paging, then the first load call must specify the <em>start</em>
7112 * and <em>limit</em> properties in the options.params property to establish the initial
7113 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7115 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7116 * and this call will return before the new data has been loaded. Perform any post-processing
7117 * in a callback function, or in a "load" event handler.</strong>
7119 * @param {Object} options An object containing properties which control loading options:<ul>
7120 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7121 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7122 * passed the following arguments:<ul>
7123 * <li>r : Roo.data.Record[]</li>
7124 * <li>options: Options object from the load call</li>
7125 * <li>success: Boolean success indicator</li></ul></li>
7126 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7127 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7130 load : function(options){
7131 options = options || {};
7132 if(this.fireEvent("beforeload", this, options) !== false){
7133 this.storeOptions(options);
7134 var p = Roo.apply(options.params || {}, this.baseParams);
7135 // if meta was not loaded from remote source.. try requesting it.
7136 if (!this.reader.metaFromRemote) {
7139 if(this.sortInfo && this.remoteSort){
7140 var pn = this.paramNames;
7141 p[pn["sort"]] = this.sortInfo.field;
7142 p[pn["dir"]] = this.sortInfo.direction;
7144 if (this.multiSort) {
7145 var pn = this.paramNames;
7146 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7149 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7154 * Reloads the Record cache from the configured Proxy using the configured Reader and
7155 * the options from the last load operation performed.
7156 * @param {Object} options (optional) An object containing properties which may override the options
7157 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7158 * the most recently used options are reused).
7160 reload : function(options){
7161 this.load(Roo.applyIf(options||{}, this.lastOptions));
7165 // Called as a callback by the Reader during a load operation.
7166 loadRecords : function(o, options, success){
7167 if(!o || success === false){
7168 if(success !== false){
7169 this.fireEvent("load", this, [], options, o);
7171 if(options.callback){
7172 options.callback.call(options.scope || this, [], options, false);
7176 // if data returned failure - throw an exception.
7177 if (o.success === false) {
7178 // show a message if no listener is registered.
7179 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7180 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7182 // loadmask wil be hooked into this..
7183 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7186 var r = o.records, t = o.totalRecords || r.length;
7188 this.fireEvent("beforeloadadd", this, r, options, o);
7190 if(!options || options.add !== true){
7191 if(this.pruneModifiedRecords){
7194 for(var i = 0, len = r.length; i < len; i++){
7198 this.data = this.snapshot;
7199 delete this.snapshot;
7202 this.data.addAll(r);
7203 this.totalLength = t;
7205 this.fireEvent("datachanged", this);
7207 this.totalLength = Math.max(t, this.data.length+r.length);
7210 this.fireEvent("load", this, r, options, o);
7211 if(options.callback){
7212 options.callback.call(options.scope || this, r, options, true);
7218 * Loads data from a passed data block. A Reader which understands the format of the data
7219 * must have been configured in the constructor.
7220 * @param {Object} data The data block from which to read the Records. The format of the data expected
7221 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7222 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7224 loadData : function(o, append){
7225 var r = this.reader.readRecords(o);
7226 this.loadRecords(r, {add: append}, true);
7230 * Gets the number of cached records.
7232 * <em>If using paging, this may not be the total size of the dataset. If the data object
7233 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7234 * the data set size</em>
7236 getCount : function(){
7237 return this.data.length || 0;
7241 * Gets the total number of records in the dataset as returned by the server.
7243 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7244 * the dataset size</em>
7246 getTotalCount : function(){
7247 return this.totalLength || 0;
7251 * Returns the sort state of the Store as an object with two properties:
7253 field {String} The name of the field by which the Records are sorted
7254 direction {String} The sort order, "ASC" or "DESC"
7257 getSortState : function(){
7258 return this.sortInfo;
7262 applySort : function(){
7263 if(this.sortInfo && !this.remoteSort){
7264 var s = this.sortInfo, f = s.field;
7265 var st = this.fields.get(f).sortType;
7266 var fn = function(r1, r2){
7267 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7268 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7270 this.data.sort(s.direction, fn);
7271 if(this.snapshot && this.snapshot != this.data){
7272 this.snapshot.sort(s.direction, fn);
7278 * Sets the default sort column and order to be used by the next load operation.
7279 * @param {String} fieldName The name of the field to sort by.
7280 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7282 setDefaultSort : function(field, dir){
7283 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7288 * If remote sorting is used, the sort is performed on the server, and the cache is
7289 * reloaded. If local sorting is used, the cache is sorted internally.
7290 * @param {String} fieldName The name of the field to sort by.
7291 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7293 sort : function(fieldName, dir){
7294 var f = this.fields.get(fieldName);
7296 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7298 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7299 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7304 this.sortToggle[f.name] = dir;
7305 this.sortInfo = {field: f.name, direction: dir};
7306 if(!this.remoteSort){
7308 this.fireEvent("datachanged", this);
7310 this.load(this.lastOptions);
7315 * Calls the specified function for each of the Records in the cache.
7316 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7317 * Returning <em>false</em> aborts and exits the iteration.
7318 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7320 each : function(fn, scope){
7321 this.data.each(fn, scope);
7325 * Gets all records modified since the last commit. Modified records are persisted across load operations
7326 * (e.g., during paging).
7327 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7329 getModifiedRecords : function(){
7330 return this.modified;
7334 createFilterFn : function(property, value, anyMatch){
7335 if(!value.exec){ // not a regex
7336 value = String(value);
7337 if(value.length == 0){
7340 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7343 return value.test(r.data[property]);
7348 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7349 * @param {String} property A field on your records
7350 * @param {Number} start The record index to start at (defaults to 0)
7351 * @param {Number} end The last record index to include (defaults to length - 1)
7352 * @return {Number} The sum
7354 sum : function(property, start, end){
7355 var rs = this.data.items, v = 0;
7357 end = (end || end === 0) ? end : rs.length-1;
7359 for(var i = start; i <= end; i++){
7360 v += (rs[i].data[property] || 0);
7366 * Filter the records by a specified property.
7367 * @param {String} field A field on your records
7368 * @param {String/RegExp} value Either a string that the field
7369 * should start with or a RegExp to test against the field
7370 * @param {Boolean} anyMatch True to match any part not just the beginning
7372 filter : function(property, value, anyMatch){
7373 var fn = this.createFilterFn(property, value, anyMatch);
7374 return fn ? this.filterBy(fn) : this.clearFilter();
7378 * Filter by a function. The specified function will be called with each
7379 * record in this data source. If the function returns true the record is included,
7380 * otherwise it is filtered.
7381 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7382 * @param {Object} scope (optional) The scope of the function (defaults to this)
7384 filterBy : function(fn, scope){
7385 this.snapshot = this.snapshot || this.data;
7386 this.data = this.queryBy(fn, scope||this);
7387 this.fireEvent("datachanged", this);
7391 * Query the records by a specified property.
7392 * @param {String} field A field on your records
7393 * @param {String/RegExp} value Either a string that the field
7394 * should start with or a RegExp to test against the field
7395 * @param {Boolean} anyMatch True to match any part not just the beginning
7396 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7398 query : function(property, value, anyMatch){
7399 var fn = this.createFilterFn(property, value, anyMatch);
7400 return fn ? this.queryBy(fn) : this.data.clone();
7404 * Query by a function. The specified function will be called with each
7405 * record in this data source. If the function returns true the record is included
7407 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7408 * @param {Object} scope (optional) The scope of the function (defaults to this)
7409 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7411 queryBy : function(fn, scope){
7412 var data = this.snapshot || this.data;
7413 return data.filterBy(fn, scope||this);
7417 * Collects unique values for a particular dataIndex from this store.
7418 * @param {String} dataIndex The property to collect
7419 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7420 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7421 * @return {Array} An array of the unique values
7423 collect : function(dataIndex, allowNull, bypassFilter){
7424 var d = (bypassFilter === true && this.snapshot) ?
7425 this.snapshot.items : this.data.items;
7426 var v, sv, r = [], l = {};
7427 for(var i = 0, len = d.length; i < len; i++){
7428 v = d[i].data[dataIndex];
7430 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7439 * Revert to a view of the Record cache with no filtering applied.
7440 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7442 clearFilter : function(suppressEvent){
7443 if(this.snapshot && this.snapshot != this.data){
7444 this.data = this.snapshot;
7445 delete this.snapshot;
7446 if(suppressEvent !== true){
7447 this.fireEvent("datachanged", this);
7453 afterEdit : function(record){
7454 if(this.modified.indexOf(record) == -1){
7455 this.modified.push(record);
7457 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7461 afterReject : function(record){
7462 this.modified.remove(record);
7463 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7467 afterCommit : function(record){
7468 this.modified.remove(record);
7469 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7473 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7474 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7476 commitChanges : function(){
7477 var m = this.modified.slice(0);
7479 for(var i = 0, len = m.length; i < len; i++){
7485 * Cancel outstanding changes on all changed records.
7487 rejectChanges : function(){
7488 var m = this.modified.slice(0);
7490 for(var i = 0, len = m.length; i < len; i++){
7495 onMetaChange : function(meta, rtype, o){
7496 this.recordType = rtype;
7497 this.fields = rtype.prototype.fields;
7498 delete this.snapshot;
7499 this.sortInfo = meta.sortInfo || this.sortInfo;
7501 this.fireEvent('metachange', this, this.reader.meta);
7504 moveIndex : function(data, type)
7506 var index = this.indexOf(data);
7508 var newIndex = index + type;
7512 this.insert(newIndex, data);
7517 * Ext JS Library 1.1.1
7518 * Copyright(c) 2006-2007, Ext JS, LLC.
7520 * Originally Released Under LGPL - original licence link has changed is not relivant.
7523 * <script type="text/javascript">
7527 * @class Roo.data.SimpleStore
7528 * @extends Roo.data.Store
7529 * Small helper class to make creating Stores from Array data easier.
7530 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7531 * @cfg {Array} fields An array of field definition objects, or field name strings.
7532 * @cfg {Array} data The multi-dimensional array of data
7534 * @param {Object} config
7536 Roo.data.SimpleStore = function(config){
7537 Roo.data.SimpleStore.superclass.constructor.call(this, {
7539 reader: new Roo.data.ArrayReader({
7542 Roo.data.Record.create(config.fields)
7544 proxy : new Roo.data.MemoryProxy(config.data)
7548 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7550 * Ext JS Library 1.1.1
7551 * Copyright(c) 2006-2007, Ext JS, LLC.
7553 * Originally Released Under LGPL - original licence link has changed is not relivant.
7556 * <script type="text/javascript">
7561 * @extends Roo.data.Store
7562 * @class Roo.data.JsonStore
7563 * Small helper class to make creating Stores for JSON data easier. <br/>
7565 var store = new Roo.data.JsonStore({
7566 url: 'get-images.php',
7568 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
7571 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
7572 * JsonReader and HttpProxy (unless inline data is provided).</b>
7573 * @cfg {Array} fields An array of field definition objects, or field name strings.
7575 * @param {Object} config
7577 Roo.data.JsonStore = function(c){
7578 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
7579 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
7580 reader: new Roo.data.JsonReader(c, c.fields)
7583 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
7585 * Ext JS Library 1.1.1
7586 * Copyright(c) 2006-2007, Ext JS, LLC.
7588 * Originally Released Under LGPL - original licence link has changed is not relivant.
7591 * <script type="text/javascript">
7595 Roo.data.Field = function(config){
7596 if(typeof config == "string"){
7597 config = {name: config};
7599 Roo.apply(this, config);
7605 var st = Roo.data.SortTypes;
7606 // named sortTypes are supported, here we look them up
7607 if(typeof this.sortType == "string"){
7608 this.sortType = st[this.sortType];
7611 // set default sortType for strings and dates
7615 this.sortType = st.asUCString;
7618 this.sortType = st.asDate;
7621 this.sortType = st.none;
7626 var stripRe = /[\$,%]/g;
7628 // prebuilt conversion function for this field, instead of
7629 // switching every time we're reading a value
7631 var cv, dateFormat = this.dateFormat;
7636 cv = function(v){ return v; };
7639 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
7643 return v !== undefined && v !== null && v !== '' ?
7644 parseInt(String(v).replace(stripRe, ""), 10) : '';
7649 return v !== undefined && v !== null && v !== '' ?
7650 parseFloat(String(v).replace(stripRe, ""), 10) : '';
7655 cv = function(v){ return v === true || v === "true" || v == 1; };
7662 if(v instanceof Date){
7666 if(dateFormat == "timestamp"){
7667 return new Date(v*1000);
7669 return Date.parseDate(v, dateFormat);
7671 var parsed = Date.parse(v);
7672 return parsed ? new Date(parsed) : null;
7681 Roo.data.Field.prototype = {
7689 * Ext JS Library 1.1.1
7690 * Copyright(c) 2006-2007, Ext JS, LLC.
7692 * Originally Released Under LGPL - original licence link has changed is not relivant.
7695 * <script type="text/javascript">
7698 // Base class for reading structured data from a data source. This class is intended to be
7699 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
7702 * @class Roo.data.DataReader
7703 * Base class for reading structured data from a data source. This class is intended to be
7704 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
7707 Roo.data.DataReader = function(meta, recordType){
7711 this.recordType = recordType instanceof Array ?
7712 Roo.data.Record.create(recordType) : recordType;
7715 Roo.data.DataReader.prototype = {
7717 * Create an empty record
7718 * @param {Object} data (optional) - overlay some values
7719 * @return {Roo.data.Record} record created.
7721 newRow : function(d) {
7723 this.recordType.prototype.fields.each(function(c) {
7725 case 'int' : da[c.name] = 0; break;
7726 case 'date' : da[c.name] = new Date(); break;
7727 case 'float' : da[c.name] = 0.0; break;
7728 case 'boolean' : da[c.name] = false; break;
7729 default : da[c.name] = ""; break;
7733 return new this.recordType(Roo.apply(da, d));
7738 * Ext JS Library 1.1.1
7739 * Copyright(c) 2006-2007, Ext JS, LLC.
7741 * Originally Released Under LGPL - original licence link has changed is not relivant.
7744 * <script type="text/javascript">
7748 * @class Roo.data.DataProxy
7749 * @extends Roo.data.Observable
7750 * This class is an abstract base class for implementations which provide retrieval of
7751 * unformatted data objects.<br>
7753 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
7754 * (of the appropriate type which knows how to parse the data object) to provide a block of
7755 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
7757 * Custom implementations must implement the load method as described in
7758 * {@link Roo.data.HttpProxy#load}.
7760 Roo.data.DataProxy = function(){
7764 * Fires before a network request is made to retrieve a data object.
7765 * @param {Object} This DataProxy object.
7766 * @param {Object} params The params parameter to the load function.
7771 * Fires before the load method's callback is called.
7772 * @param {Object} This DataProxy object.
7773 * @param {Object} o The data object.
7774 * @param {Object} arg The callback argument object passed to the load function.
7778 * @event loadexception
7779 * Fires if an Exception occurs during data retrieval.
7780 * @param {Object} This DataProxy object.
7781 * @param {Object} o The data object.
7782 * @param {Object} arg The callback argument object passed to the load function.
7783 * @param {Object} e The Exception.
7785 loadexception : true
7787 Roo.data.DataProxy.superclass.constructor.call(this);
7790 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7793 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7797 * Ext JS Library 1.1.1
7798 * Copyright(c) 2006-2007, Ext JS, LLC.
7800 * Originally Released Under LGPL - original licence link has changed is not relivant.
7803 * <script type="text/javascript">
7806 * @class Roo.data.MemoryProxy
7807 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7808 * to the Reader when its load method is called.
7810 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7812 Roo.data.MemoryProxy = function(data){
7816 Roo.data.MemoryProxy.superclass.constructor.call(this);
7820 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7822 * Load data from the requested source (in this case an in-memory
7823 * data object passed to the constructor), read the data object into
7824 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7825 * process that block using the passed callback.
7826 * @param {Object} params This parameter is not used by the MemoryProxy class.
7827 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7828 * object into a block of Roo.data.Records.
7829 * @param {Function} callback The function into which to pass the block of Roo.data.records.
7830 * The function must be passed <ul>
7831 * <li>The Record block object</li>
7832 * <li>The "arg" argument from the load function</li>
7833 * <li>A boolean success indicator</li>
7835 * @param {Object} scope The scope in which to call the callback
7836 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7838 load : function(params, reader, callback, scope, arg){
7839 params = params || {};
7842 result = reader.readRecords(this.data);
7844 this.fireEvent("loadexception", this, arg, null, e);
7845 callback.call(scope, null, arg, false);
7848 callback.call(scope, result, arg, true);
7852 update : function(params, records){
7857 * Ext JS Library 1.1.1
7858 * Copyright(c) 2006-2007, Ext JS, LLC.
7860 * Originally Released Under LGPL - original licence link has changed is not relivant.
7863 * <script type="text/javascript">
7866 * @class Roo.data.HttpProxy
7867 * @extends Roo.data.DataProxy
7868 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7869 * configured to reference a certain URL.<br><br>
7871 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7872 * from which the running page was served.<br><br>
7874 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7876 * Be aware that to enable the browser to parse an XML document, the server must set
7877 * the Content-Type header in the HTTP response to "text/xml".
7879 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7880 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7881 * will be used to make the request.
7883 Roo.data.HttpProxy = function(conn){
7884 Roo.data.HttpProxy.superclass.constructor.call(this);
7885 // is conn a conn config or a real conn?
7887 this.useAjax = !conn || !conn.events;
7891 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7892 // thse are take from connection...
7895 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7898 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7899 * extra parameters to each request made by this object. (defaults to undefined)
7902 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7903 * to each request made by this object. (defaults to undefined)
7906 * @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)
7909 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7912 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7918 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7922 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7923 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7924 * a finer-grained basis than the DataProxy events.
7926 getConnection : function(){
7927 return this.useAjax ? Roo.Ajax : this.conn;
7931 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7932 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7933 * process that block using the passed callback.
7934 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7935 * for the request to the remote server.
7936 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7937 * object into a block of Roo.data.Records.
7938 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7939 * The function must be passed <ul>
7940 * <li>The Record block object</li>
7941 * <li>The "arg" argument from the load function</li>
7942 * <li>A boolean success indicator</li>
7944 * @param {Object} scope The scope in which to call the callback
7945 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7947 load : function(params, reader, callback, scope, arg){
7948 if(this.fireEvent("beforeload", this, params) !== false){
7950 params : params || {},
7952 callback : callback,
7957 callback : this.loadResponse,
7961 Roo.applyIf(o, this.conn);
7962 if(this.activeRequest){
7963 Roo.Ajax.abort(this.activeRequest);
7965 this.activeRequest = Roo.Ajax.request(o);
7967 this.conn.request(o);
7970 callback.call(scope||this, null, arg, false);
7975 loadResponse : function(o, success, response){
7976 delete this.activeRequest;
7978 this.fireEvent("loadexception", this, o, response);
7979 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7984 result = o.reader.read(response);
7986 this.fireEvent("loadexception", this, o, response, e);
7987 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7991 this.fireEvent("load", this, o, o.request.arg);
7992 o.request.callback.call(o.request.scope, result, o.request.arg, true);
7996 update : function(dataSet){
8001 updateResponse : function(dataSet){
8006 * Ext JS Library 1.1.1
8007 * Copyright(c) 2006-2007, Ext JS, LLC.
8009 * Originally Released Under LGPL - original licence link has changed is not relivant.
8012 * <script type="text/javascript">
8016 * @class Roo.data.ScriptTagProxy
8017 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8018 * other than the originating domain of the running page.<br><br>
8020 * <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
8021 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8023 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8024 * source code that is used as the source inside a <script> tag.<br><br>
8026 * In order for the browser to process the returned data, the server must wrap the data object
8027 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8028 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8029 * depending on whether the callback name was passed:
8032 boolean scriptTag = false;
8033 String cb = request.getParameter("callback");
8036 response.setContentType("text/javascript");
8038 response.setContentType("application/x-json");
8040 Writer out = response.getWriter();
8042 out.write(cb + "(");
8044 out.print(dataBlock.toJsonString());
8051 * @param {Object} config A configuration object.
8053 Roo.data.ScriptTagProxy = function(config){
8054 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8055 Roo.apply(this, config);
8056 this.head = document.getElementsByTagName("head")[0];
8059 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8061 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8063 * @cfg {String} url The URL from which to request the data object.
8066 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8070 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8071 * the server the name of the callback function set up by the load call to process the returned data object.
8072 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8073 * javascript output which calls this named function passing the data object as its only parameter.
8075 callbackParam : "callback",
8077 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8078 * name to the request.
8083 * Load data from the configured URL, read the data object into
8084 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8085 * process that block using the passed callback.
8086 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8087 * for the request to the remote server.
8088 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8089 * object into a block of Roo.data.Records.
8090 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8091 * The function must be passed <ul>
8092 * <li>The Record block object</li>
8093 * <li>The "arg" argument from the load function</li>
8094 * <li>A boolean success indicator</li>
8096 * @param {Object} scope The scope in which to call the callback
8097 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8099 load : function(params, reader, callback, scope, arg){
8100 if(this.fireEvent("beforeload", this, params) !== false){
8102 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8105 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8107 url += "&_dc=" + (new Date().getTime());
8109 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8112 cb : "stcCallback"+transId,
8113 scriptId : "stcScript"+transId,
8117 callback : callback,
8123 window[trans.cb] = function(o){
8124 conn.handleResponse(o, trans);
8127 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8129 if(this.autoAbort !== false){
8133 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8135 var script = document.createElement("script");
8136 script.setAttribute("src", url);
8137 script.setAttribute("type", "text/javascript");
8138 script.setAttribute("id", trans.scriptId);
8139 this.head.appendChild(script);
8143 callback.call(scope||this, null, arg, false);
8148 isLoading : function(){
8149 return this.trans ? true : false;
8153 * Abort the current server request.
8156 if(this.isLoading()){
8157 this.destroyTrans(this.trans);
8162 destroyTrans : function(trans, isLoaded){
8163 this.head.removeChild(document.getElementById(trans.scriptId));
8164 clearTimeout(trans.timeoutId);
8166 window[trans.cb] = undefined;
8168 delete window[trans.cb];
8171 // if hasn't been loaded, wait for load to remove it to prevent script error
8172 window[trans.cb] = function(){
8173 window[trans.cb] = undefined;
8175 delete window[trans.cb];
8182 handleResponse : function(o, trans){
8184 this.destroyTrans(trans, true);
8187 result = trans.reader.readRecords(o);
8189 this.fireEvent("loadexception", this, o, trans.arg, e);
8190 trans.callback.call(trans.scope||window, null, trans.arg, false);
8193 this.fireEvent("load", this, o, trans.arg);
8194 trans.callback.call(trans.scope||window, result, trans.arg, true);
8198 handleFailure : function(trans){
8200 this.destroyTrans(trans, false);
8201 this.fireEvent("loadexception", this, null, trans.arg);
8202 trans.callback.call(trans.scope||window, null, trans.arg, false);
8206 * Ext JS Library 1.1.1
8207 * Copyright(c) 2006-2007, Ext JS, LLC.
8209 * Originally Released Under LGPL - original licence link has changed is not relivant.
8212 * <script type="text/javascript">
8216 * @class Roo.data.JsonReader
8217 * @extends Roo.data.DataReader
8218 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8219 * based on mappings in a provided Roo.data.Record constructor.
8221 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8222 * in the reply previously.
8227 var RecordDef = Roo.data.Record.create([
8228 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8229 {name: 'occupation'} // This field will use "occupation" as the mapping.
8231 var myReader = new Roo.data.JsonReader({
8232 totalProperty: "results", // The property which contains the total dataset size (optional)
8233 root: "rows", // The property which contains an Array of row objects
8234 id: "id" // The property within each row object that provides an ID for the record (optional)
8238 * This would consume a JSON file like this:
8240 { 'results': 2, 'rows': [
8241 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8242 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8245 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8246 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8247 * paged from the remote server.
8248 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8249 * @cfg {String} root name of the property which contains the Array of row objects.
8250 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8252 * Create a new JsonReader
8253 * @param {Object} meta Metadata configuration options
8254 * @param {Object} recordType Either an Array of field definition objects,
8255 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8257 Roo.data.JsonReader = function(meta, recordType){
8260 // set some defaults:
8262 totalProperty: 'total',
8263 successProperty : 'success',
8268 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8270 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8273 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8274 * Used by Store query builder to append _requestMeta to params.
8277 metaFromRemote : false,
8279 * This method is only used by a DataProxy which has retrieved data from a remote server.
8280 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8281 * @return {Object} data A data block which is used by an Roo.data.Store object as
8282 * a cache of Roo.data.Records.
8284 read : function(response){
8285 var json = response.responseText;
8287 var o = /* eval:var:o */ eval("("+json+")");
8289 throw {message: "JsonReader.read: Json object not found"};
8295 this.metaFromRemote = true;
8296 this.meta = o.metaData;
8297 this.recordType = Roo.data.Record.create(o.metaData.fields);
8298 this.onMetaChange(this.meta, this.recordType, o);
8300 return this.readRecords(o);
8303 // private function a store will implement
8304 onMetaChange : function(meta, recordType, o){
8311 simpleAccess: function(obj, subsc) {
8318 getJsonAccessor: function(){
8320 return function(expr) {
8322 return(re.test(expr))
8323 ? new Function("obj", "return obj." + expr)
8333 * Create a data block containing Roo.data.Records from an XML document.
8334 * @param {Object} o An object which contains an Array of row objects in the property specified
8335 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8336 * which contains the total size of the dataset.
8337 * @return {Object} data A data block which is used by an Roo.data.Store object as
8338 * a cache of Roo.data.Records.
8340 readRecords : function(o){
8342 * After any data loads, the raw JSON data is available for further custom processing.
8346 var s = this.meta, Record = this.recordType,
8347 f = Record.prototype.fields, fi = f.items, fl = f.length;
8349 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8351 if(s.totalProperty) {
8352 this.getTotal = this.getJsonAccessor(s.totalProperty);
8354 if(s.successProperty) {
8355 this.getSuccess = this.getJsonAccessor(s.successProperty);
8357 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8359 var g = this.getJsonAccessor(s.id);
8360 this.getId = function(rec) {
8362 return (r === undefined || r === "") ? null : r;
8365 this.getId = function(){return null;};
8368 for(var jj = 0; jj < fl; jj++){
8370 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8371 this.ef[jj] = this.getJsonAccessor(map);
8375 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8376 if(s.totalProperty){
8377 var vt = parseInt(this.getTotal(o), 10);
8382 if(s.successProperty){
8383 var vs = this.getSuccess(o);
8384 if(vs === false || vs === 'false'){
8389 for(var i = 0; i < c; i++){
8392 var id = this.getId(n);
8393 for(var j = 0; j < fl; j++){
8395 var v = this.ef[j](n);
8397 Roo.log('missing convert for ' + f.name);
8401 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8403 var record = new Record(values, id);
8405 records[i] = record;
8411 totalRecords : totalRecords
8416 * Ext JS Library 1.1.1
8417 * Copyright(c) 2006-2007, Ext JS, LLC.
8419 * Originally Released Under LGPL - original licence link has changed is not relivant.
8422 * <script type="text/javascript">
8426 * @class Roo.data.ArrayReader
8427 * @extends Roo.data.DataReader
8428 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8429 * Each element of that Array represents a row of data fields. The
8430 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8431 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8435 var RecordDef = Roo.data.Record.create([
8436 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8437 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8439 var myReader = new Roo.data.ArrayReader({
8440 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8444 * This would consume an Array like this:
8446 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8448 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8450 * Create a new JsonReader
8451 * @param {Object} meta Metadata configuration options.
8452 * @param {Object} recordType Either an Array of field definition objects
8453 * as specified to {@link Roo.data.Record#create},
8454 * or an {@link Roo.data.Record} object
8455 * created using {@link Roo.data.Record#create}.
8457 Roo.data.ArrayReader = function(meta, recordType){
8458 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8461 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8463 * Create a data block containing Roo.data.Records from an XML document.
8464 * @param {Object} o An Array of row objects which represents the dataset.
8465 * @return {Object} data A data block which is used by an Roo.data.Store object as
8466 * a cache of Roo.data.Records.
8468 readRecords : function(o){
8469 var sid = this.meta ? this.meta.id : null;
8470 var recordType = this.recordType, fields = recordType.prototype.fields;
8473 for(var i = 0; i < root.length; i++){
8476 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8477 for(var j = 0, jlen = fields.length; j < jlen; j++){
8478 var f = fields.items[j];
8479 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8480 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8484 var record = new recordType(values, id);
8486 records[records.length] = record;
8490 totalRecords : records.length
8499 * @class Roo.bootstrap.ComboBox
8500 * @extends Roo.bootstrap.TriggerField
8501 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8502 * @cfg {Boolean} append (true|false) default false
8504 * Create a new ComboBox.
8505 * @param {Object} config Configuration options
8507 Roo.bootstrap.ComboBox = function(config){
8508 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8512 * Fires when the dropdown list is expanded
8513 * @param {Roo.bootstrap.ComboBox} combo This combo box
8518 * Fires when the dropdown list is collapsed
8519 * @param {Roo.bootstrap.ComboBox} combo This combo box
8523 * @event beforeselect
8524 * Fires before a list item is selected. Return false to cancel the selection.
8525 * @param {Roo.bootstrap.ComboBox} combo This combo box
8526 * @param {Roo.data.Record} record The data record returned from the underlying store
8527 * @param {Number} index The index of the selected item in the dropdown list
8529 'beforeselect' : true,
8532 * Fires when a list item is selected
8533 * @param {Roo.bootstrap.ComboBox} combo This combo box
8534 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8535 * @param {Number} index The index of the selected item in the dropdown list
8539 * @event beforequery
8540 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8541 * The event object passed has these properties:
8542 * @param {Roo.bootstrap.ComboBox} combo This combo box
8543 * @param {String} query The query
8544 * @param {Boolean} forceAll true to force "all" query
8545 * @param {Boolean} cancel true to cancel the query
8546 * @param {Object} e The query event object
8548 'beforequery': true,
8551 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8552 * @param {Roo.bootstrap.ComboBox} combo This combo box
8557 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
8558 * @param {Roo.bootstrap.ComboBox} combo This combo box
8559 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
8564 * Fires when the remove value from the combobox array
8565 * @param {Roo.bootstrap.ComboBox} combo This combo box
8572 this.selectedIndex = -1;
8573 if(this.mode == 'local'){
8574 if(config.queryDelay === undefined){
8575 this.queryDelay = 10;
8577 if(config.minChars === undefined){
8583 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
8586 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
8587 * rendering into an Roo.Editor, defaults to false)
8590 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
8591 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
8594 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
8597 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
8598 * the dropdown list (defaults to undefined, with no header element)
8602 * @cfg {String/Roo.Template} tpl The template to use to render the output
8606 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
8608 listWidth: undefined,
8610 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
8611 * mode = 'remote' or 'text' if mode = 'local')
8613 displayField: undefined,
8615 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
8616 * mode = 'remote' or 'value' if mode = 'local').
8617 * Note: use of a valueField requires the user make a selection
8618 * in order for a value to be mapped.
8620 valueField: undefined,
8624 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
8625 * field's data value (defaults to the underlying DOM element's name)
8627 hiddenName: undefined,
8629 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
8633 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
8635 selectedClass: 'active',
8638 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
8642 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
8643 * anchor positions (defaults to 'tl-bl')
8645 listAlign: 'tl-bl?',
8647 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
8651 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
8652 * query specified by the allQuery config option (defaults to 'query')
8654 triggerAction: 'query',
8656 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
8657 * (defaults to 4, does not apply if editable = false)
8661 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
8662 * delay (typeAheadDelay) if it matches a known value (defaults to false)
8666 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
8667 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
8671 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
8672 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
8676 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
8677 * when editable = true (defaults to false)
8679 selectOnFocus:false,
8681 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
8683 queryParam: 'query',
8685 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
8686 * when mode = 'remote' (defaults to 'Loading...')
8688 loadingText: 'Loading...',
8690 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
8694 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
8698 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
8699 * traditional select (defaults to true)
8703 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
8707 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
8711 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
8712 * listWidth has a higher value)
8716 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
8717 * allow the user to set arbitrary text into the field (defaults to false)
8719 forceSelection:false,
8721 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
8722 * if typeAhead = true (defaults to 250)
8724 typeAheadDelay : 250,
8726 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
8727 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
8729 valueNotFoundText : undefined,
8731 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8736 * @cfg {Boolean} disableClear Disable showing of clear button.
8738 disableClear : false,
8740 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8742 alwaysQuery : false,
8745 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
8759 // element that contains real text value.. (when hidden is used..)
8762 initEvents: function(){
8765 throw "can not find store for combo";
8767 this.store = Roo.factory(this.store, Roo.data);
8771 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
8774 if(this.hiddenName){
8776 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
8778 this.hiddenField.dom.value =
8779 this.hiddenValue !== undefined ? this.hiddenValue :
8780 this.value !== undefined ? this.value : '';
8782 // prevent input submission
8783 this.el.dom.removeAttribute('name');
8784 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8789 // this.el.dom.setAttribute('autocomplete', 'off');
8792 var cls = 'x-combo-list';
8793 this.list = this.el.select('ul.dropdown-menu',true).first();
8795 //this.list = new Roo.Layer({
8796 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8799 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8800 this.list.setWidth(lw);
8802 this.list.on('mouseover', this.onViewOver, this);
8803 this.list.on('mousemove', this.onViewMove, this);
8805 this.list.on('scroll', this.onViewScroll, this);
8808 this.list.swallowEvent('mousewheel');
8809 this.assetHeight = 0;
8812 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8813 this.assetHeight += this.header.getHeight();
8816 this.innerList = this.list.createChild({cls:cls+'-inner'});
8817 this.innerList.on('mouseover', this.onViewOver, this);
8818 this.innerList.on('mousemove', this.onViewMove, this);
8819 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8821 if(this.allowBlank && !this.pageSize && !this.disableClear){
8822 this.footer = this.list.createChild({cls:cls+'-ft'});
8823 this.pageTb = new Roo.Toolbar(this.footer);
8827 this.footer = this.list.createChild({cls:cls+'-ft'});
8828 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
8829 {pageSize: this.pageSize});
8833 if (this.pageTb && this.allowBlank && !this.disableClear) {
8835 this.pageTb.add(new Roo.Toolbar.Fill(), {
8836 cls: 'x-btn-icon x-btn-clear',
8842 _this.onSelect(false, -1);
8847 this.assetHeight += this.footer.getHeight();
8852 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8855 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8856 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8858 //this.view.wrapEl.setDisplayed(false);
8859 this.view.on('click', this.onViewClick, this);
8863 this.store.on('beforeload', this.onBeforeLoad, this);
8864 this.store.on('load', this.onLoad, this);
8865 this.store.on('loadexception', this.onLoadException, this);
8868 this.resizer = new Roo.Resizable(this.list, {
8869 pinned:true, handles:'se'
8871 this.resizer.on('resize', function(r, w, h){
8872 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8874 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8875 this.restrictHeight();
8877 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8881 this.editable = true;
8882 this.setEditable(false);
8887 if (typeof(this.events.add.listeners) != 'undefined') {
8889 this.addicon = this.wrap.createChild(
8890 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8892 this.addicon.on('click', function(e) {
8893 this.fireEvent('add', this);
8896 if (typeof(this.events.edit.listeners) != 'undefined') {
8898 this.editicon = this.wrap.createChild(
8899 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8901 this.editicon.setStyle('margin-left', '40px');
8903 this.editicon.on('click', function(e) {
8905 // we fire even if inothing is selected..
8906 this.fireEvent('edit', this, this.lastData );
8912 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8914 this.inKeyMode = true;
8918 "down" : function(e){
8919 if(!this.isExpanded()){
8920 this.onTriggerClick();
8922 this.inKeyMode = true;
8927 "enter" : function(e){
8932 "esc" : function(e){
8936 "tab" : function(e){
8939 if(this.fireEvent("specialkey", this, e)){
8940 this.onViewClick(false);
8948 doRelay : function(foo, bar, hname){
8949 if(hname == 'down' || this.scope.isExpanded()){
8950 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8959 this.queryDelay = Math.max(this.queryDelay || 10,
8960 this.mode == 'local' ? 10 : 250);
8963 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8966 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8968 if(this.editable !== false){
8969 this.inputEl().on("keyup", this.onKeyUp, this);
8971 if(this.forceSelection){
8972 this.on('blur', this.doForce, this);
8976 this.choices = this.el.select('ul.select2-choices', true).first();
8977 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8981 onDestroy : function(){
8983 this.view.setStore(null);
8984 this.view.el.removeAllListeners();
8985 this.view.el.remove();
8986 this.view.purgeListeners();
8989 this.list.dom.innerHTML = '';
8992 this.store.un('beforeload', this.onBeforeLoad, this);
8993 this.store.un('load', this.onLoad, this);
8994 this.store.un('loadexception', this.onLoadException, this);
8996 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9000 fireKey : function(e){
9001 if(e.isNavKeyPress() && !this.list.isVisible()){
9002 this.fireEvent("specialkey", this, e);
9007 onResize: function(w, h){
9008 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9010 // if(typeof w != 'number'){
9011 // // we do not handle it!?!?
9014 // var tw = this.trigger.getWidth();
9015 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9016 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9018 // this.inputEl().setWidth( this.adjustWidth('input', x));
9020 // //this.trigger.setStyle('left', x+'px');
9022 // if(this.list && this.listWidth === undefined){
9023 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9024 // this.list.setWidth(lw);
9025 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9033 * Allow or prevent the user from directly editing the field text. If false is passed,
9034 * the user will only be able to select from the items defined in the dropdown list. This method
9035 * is the runtime equivalent of setting the 'editable' config option at config time.
9036 * @param {Boolean} value True to allow the user to directly edit the field text
9038 setEditable : function(value){
9039 if(value == this.editable){
9042 this.editable = value;
9044 this.inputEl().dom.setAttribute('readOnly', true);
9045 this.inputEl().on('mousedown', this.onTriggerClick, this);
9046 this.inputEl().addClass('x-combo-noedit');
9048 this.inputEl().dom.setAttribute('readOnly', false);
9049 this.inputEl().un('mousedown', this.onTriggerClick, this);
9050 this.inputEl().removeClass('x-combo-noedit');
9056 onBeforeLoad : function(combo,opts){
9061 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9063 this.restrictHeight();
9064 this.selectedIndex = -1;
9068 onLoad : function(){
9070 this.hasQuery = false;
9076 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9077 this.loading.hide();
9080 if(this.store.getCount() > 0){
9082 this.restrictHeight();
9083 if(this.lastQuery == this.allQuery){
9085 this.inputEl().dom.select();
9087 if(!this.selectByValue(this.value, true)){
9088 this.select(0, true);
9092 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9093 this.taTask.delay(this.typeAheadDelay);
9097 this.onEmptyResults();
9103 onLoadException : function()
9105 this.hasQuery = false;
9107 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9108 this.loading.hide();
9112 Roo.log(this.store.reader.jsonData);
9113 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9115 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9121 onTypeAhead : function(){
9122 if(this.store.getCount() > 0){
9123 var r = this.store.getAt(0);
9124 var newValue = r.data[this.displayField];
9125 var len = newValue.length;
9126 var selStart = this.getRawValue().length;
9128 if(selStart != len){
9129 this.setRawValue(newValue);
9130 this.selectText(selStart, newValue.length);
9136 onSelect : function(record, index){
9138 if(this.fireEvent('beforeselect', this, record, index) !== false){
9140 this.setFromData(index > -1 ? record.data : false);
9143 this.fireEvent('select', this, record, index);
9148 * Returns the currently selected field value or empty string if no value is set.
9149 * @return {String} value The selected value
9151 getValue : function(){
9154 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9157 if(this.valueField){
9158 return typeof this.value != 'undefined' ? this.value : '';
9160 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9165 * Clears any text/value currently set in the field
9167 clearValue : function(){
9168 if(this.hiddenField){
9169 this.hiddenField.dom.value = '';
9172 this.setRawValue('');
9173 this.lastSelectionText = '';
9178 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9179 * will be displayed in the field. If the value does not match the data value of an existing item,
9180 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9181 * Otherwise the field will be blank (although the value will still be set).
9182 * @param {String} value The value to match
9184 setValue : function(v){
9191 if(this.valueField){
9192 var r = this.findRecord(this.valueField, v);
9194 text = r.data[this.displayField];
9195 }else if(this.valueNotFoundText !== undefined){
9196 text = this.valueNotFoundText;
9199 this.lastSelectionText = text;
9200 if(this.hiddenField){
9201 this.hiddenField.dom.value = v;
9203 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9207 * @property {Object} the last set data for the element
9212 * Sets the value of the field based on a object which is related to the record format for the store.
9213 * @param {Object} value the value to set as. or false on reset?
9215 setFromData : function(o){
9222 var dv = ''; // display value
9223 var vv = ''; // value value..
9225 if (this.displayField) {
9226 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9228 // this is an error condition!!!
9229 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9232 if(this.valueField){
9233 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9236 if(this.hiddenField){
9237 this.hiddenField.dom.value = vv;
9239 this.lastSelectionText = dv;
9240 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9244 // no hidden field.. - we store the value in 'value', but still display
9245 // display field!!!!
9246 this.lastSelectionText = dv;
9247 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9254 // overridden so that last data is reset..
9255 this.setValue(this.originalValue);
9256 this.clearInvalid();
9257 this.lastData = false;
9259 this.view.clearSelections();
9263 findRecord : function(prop, value){
9265 if(this.store.getCount() > 0){
9266 this.store.each(function(r){
9267 if(r.data[prop] == value){
9279 // returns hidden if it's set..
9280 if (!this.rendered) {return ''};
9281 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9285 onViewMove : function(e, t){
9286 this.inKeyMode = false;
9290 onViewOver : function(e, t){
9291 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9294 var item = this.view.findItemFromChild(t);
9296 var index = this.view.indexOf(item);
9297 this.select(index, false);
9302 onViewClick : function(doFocus)
9304 var index = this.view.getSelectedIndexes()[0];
9305 var r = this.store.getAt(index);
9307 this.onSelect(r, index);
9309 if(doFocus !== false && !this.blockFocus){
9310 this.inputEl().focus();
9315 restrictHeight : function(){
9316 //this.innerList.dom.style.height = '';
9317 //var inner = this.innerList.dom;
9318 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9319 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9320 //this.list.beginUpdate();
9321 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9322 this.list.alignTo(this.inputEl(), this.listAlign);
9323 //this.list.endUpdate();
9327 onEmptyResults : function(){
9332 * Returns true if the dropdown list is expanded, else false.
9334 isExpanded : function(){
9335 return this.list.isVisible();
9339 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9340 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9341 * @param {String} value The data value of the item to select
9342 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9343 * selected item if it is not currently in view (defaults to true)
9344 * @return {Boolean} True if the value matched an item in the list, else false
9346 selectByValue : function(v, scrollIntoView){
9347 if(v !== undefined && v !== null){
9348 var r = this.findRecord(this.valueField || this.displayField, v);
9350 this.select(this.store.indexOf(r), scrollIntoView);
9358 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9359 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9360 * @param {Number} index The zero-based index of the list item to select
9361 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9362 * selected item if it is not currently in view (defaults to true)
9364 select : function(index, scrollIntoView){
9365 this.selectedIndex = index;
9366 this.view.select(index);
9367 if(scrollIntoView !== false){
9368 var el = this.view.getNode(index);
9370 //this.innerList.scrollChildIntoView(el, false);
9377 selectNext : function(){
9378 var ct = this.store.getCount();
9380 if(this.selectedIndex == -1){
9382 }else if(this.selectedIndex < ct-1){
9383 this.select(this.selectedIndex+1);
9389 selectPrev : function(){
9390 var ct = this.store.getCount();
9392 if(this.selectedIndex == -1){
9394 }else if(this.selectedIndex != 0){
9395 this.select(this.selectedIndex-1);
9401 onKeyUp : function(e){
9402 if(this.editable !== false && !e.isSpecialKey()){
9403 this.lastKey = e.getKey();
9404 this.dqTask.delay(this.queryDelay);
9409 validateBlur : function(){
9410 return !this.list || !this.list.isVisible();
9414 initQuery : function(){
9415 this.doQuery(this.getRawValue());
9419 doForce : function(){
9420 if(this.el.dom.value.length > 0){
9422 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9428 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9429 * query allowing the query action to be canceled if needed.
9430 * @param {String} query The SQL query to execute
9431 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9432 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9433 * saved in the current store (defaults to false)
9435 doQuery : function(q, forceAll){
9437 if(q === undefined || q === null){
9446 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9451 forceAll = qe.forceAll;
9452 if(forceAll === true || (q.length >= this.minChars)){
9454 this.hasQuery = true;
9456 if(this.lastQuery != q || this.alwaysQuery){
9458 if(this.mode == 'local'){
9459 this.selectedIndex = -1;
9461 this.store.clearFilter();
9463 this.store.filter(this.displayField, q);
9467 this.store.baseParams[this.queryParam] = q;
9469 var options = {params : this.getParams(q)};
9473 options.params.start = this.page * this.pageSize;
9476 this.store.load(options);
9480 this.selectedIndex = -1;
9485 this.loadNext = false;
9489 getParams : function(q){
9491 //p[this.queryParam] = q;
9495 p.limit = this.pageSize;
9501 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9503 collapse : function(){
9504 if(!this.isExpanded()){
9509 Roo.get(document).un('mousedown', this.collapseIf, this);
9510 Roo.get(document).un('mousewheel', this.collapseIf, this);
9511 if (!this.editable) {
9512 Roo.get(document).un('keydown', this.listKeyPress, this);
9514 this.fireEvent('collapse', this);
9518 collapseIf : function(e){
9519 var in_combo = e.within(this.el);
9520 var in_list = e.within(this.list);
9522 if (in_combo || in_list) {
9523 //e.stopPropagation();
9532 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9534 expand : function(){
9536 if(this.isExpanded() || !this.hasFocus){
9540 this.list.alignTo(this.inputEl(), this.listAlign);
9542 Roo.get(document).on('mousedown', this.collapseIf, this);
9543 Roo.get(document).on('mousewheel', this.collapseIf, this);
9544 if (!this.editable) {
9545 Roo.get(document).on('keydown', this.listKeyPress, this);
9548 this.fireEvent('expand', this);
9552 // Implements the default empty TriggerField.onTriggerClick function
9553 onTriggerClick : function()
9555 Roo.log('trigger click');
9562 this.loadNext = false;
9564 if(this.isExpanded()){
9566 if (!this.blockFocus) {
9567 this.inputEl().focus();
9571 this.hasFocus = true;
9572 if(this.triggerAction == 'all') {
9573 this.doQuery(this.allQuery, true);
9575 this.doQuery(this.getRawValue());
9577 if (!this.blockFocus) {
9578 this.inputEl().focus();
9582 listKeyPress : function(e)
9584 //Roo.log('listkeypress');
9585 // scroll to first matching element based on key pres..
9586 if (e.isSpecialKey()) {
9589 var k = String.fromCharCode(e.getKey()).toUpperCase();
9592 var csel = this.view.getSelectedNodes();
9593 var cselitem = false;
9595 var ix = this.view.indexOf(csel[0]);
9596 cselitem = this.store.getAt(ix);
9597 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
9603 this.store.each(function(v) {
9605 // start at existing selection.
9606 if (cselitem.id == v.id) {
9612 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
9613 match = this.store.indexOf(v);
9619 if (match === false) {
9620 return true; // no more action?
9623 this.view.select(match);
9624 var sn = Roo.get(this.view.getSelectedNodes()[0])
9625 //sn.scrollIntoView(sn.dom.parentNode, false);
9628 onViewScroll : function(e, t){
9630 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
9634 this.hasQuery = true;
9636 this.loading = this.list.select('.loading', true).first();
9638 if(this.loading === null){
9639 this.list.createChild({
9641 cls: 'loading select2-more-results select2-active',
9642 html: 'Loading more results...'
9645 this.loading = this.list.select('.loading', true).first();
9647 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
9649 this.loading.hide();
9652 this.loading.show();
9657 this.loadNext = true;
9659 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
9664 addItem : function(o)
9666 var dv = ''; // display value
9668 if (this.displayField) {
9669 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9671 // this is an error condition!!!
9672 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9679 var choice = this.choices.createChild({
9681 cls: 'select2-search-choice',
9690 cls: 'select2-search-choice-close',
9695 }, this.searchField);
9697 var close = choice.select('a.select2-search-choice-close', true).first()
9699 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
9706 this.inputEl().dom.value = '';
9710 onRemoveItem : function(e, _self, o)
9712 Roo.log('remove item');
9713 var index = this.item.indexOf(o.data) * 1;
9716 Roo.log('not this item?!');
9720 this.item.splice(index, 1);
9725 this.fireEvent('remove', this);
9729 syncValue : function()
9731 if(!this.item.length){
9738 Roo.each(this.item, function(i){
9739 if(_this.valueField){
9740 value.push(i[_this.valueField]);
9747 this.value = value.join(',');
9749 if(this.hiddenField){
9750 this.hiddenField.dom.value = this.value;
9754 clearItem : function()
9762 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
9772 * @cfg {Boolean} grow
9776 * @cfg {Number} growMin
9780 * @cfg {Number} growMax
9790 * Ext JS Library 1.1.1
9791 * Copyright(c) 2006-2007, Ext JS, LLC.
9793 * Originally Released Under LGPL - original licence link has changed is not relivant.
9796 * <script type="text/javascript">
9801 * @extends Roo.util.Observable
9802 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9803 * This class also supports single and multi selection modes. <br>
9804 * Create a data model bound view:
9806 var store = new Roo.data.Store(...);
9808 var view = new Roo.View({
9810 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9813 selectedClass: "ydataview-selected",
9817 // listen for node click?
9818 view.on("click", function(vw, index, node, e){
9819 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9823 dataModel.load("foobar.xml");
9825 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9827 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9828 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9830 * Note: old style constructor is still suported (container, template, config)
9834 * @param {Object} config The config object
9837 Roo.View = function(config, depreciated_tpl, depreciated_config){
9839 if (typeof(depreciated_tpl) == 'undefined') {
9840 // new way.. - universal constructor.
9841 Roo.apply(this, config);
9842 this.el = Roo.get(this.el);
9845 this.el = Roo.get(config);
9846 this.tpl = depreciated_tpl;
9847 Roo.apply(this, depreciated_config);
9849 this.wrapEl = this.el.wrap().wrap();
9850 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9853 if(typeof(this.tpl) == "string"){
9854 this.tpl = new Roo.Template(this.tpl);
9856 // support xtype ctors..
9857 this.tpl = new Roo.factory(this.tpl, Roo);
9869 * @event beforeclick
9870 * Fires before a click is processed. Returns false to cancel the default action.
9871 * @param {Roo.View} this
9872 * @param {Number} index The index of the target node
9873 * @param {HTMLElement} node The target node
9874 * @param {Roo.EventObject} e The raw event object
9876 "beforeclick" : true,
9879 * Fires when a template node is clicked.
9880 * @param {Roo.View} this
9881 * @param {Number} index The index of the target node
9882 * @param {HTMLElement} node The target node
9883 * @param {Roo.EventObject} e The raw event object
9888 * Fires when a template node is double clicked.
9889 * @param {Roo.View} this
9890 * @param {Number} index The index of the target node
9891 * @param {HTMLElement} node The target node
9892 * @param {Roo.EventObject} e The raw event object
9896 * @event contextmenu
9897 * Fires when a template node is right clicked.
9898 * @param {Roo.View} this
9899 * @param {Number} index The index of the target node
9900 * @param {HTMLElement} node The target node
9901 * @param {Roo.EventObject} e The raw event object
9903 "contextmenu" : true,
9905 * @event selectionchange
9906 * Fires when the selected nodes change.
9907 * @param {Roo.View} this
9908 * @param {Array} selections Array of the selected nodes
9910 "selectionchange" : true,
9913 * @event beforeselect
9914 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9915 * @param {Roo.View} this
9916 * @param {HTMLElement} node The node to be selected
9917 * @param {Array} selections Array of currently selected nodes
9919 "beforeselect" : true,
9921 * @event preparedata
9922 * Fires on every row to render, to allow you to change the data.
9923 * @param {Roo.View} this
9924 * @param {Object} data to be rendered (change this)
9926 "preparedata" : true
9934 "click": this.onClick,
9935 "dblclick": this.onDblClick,
9936 "contextmenu": this.onContextMenu,
9940 this.selections = [];
9942 this.cmp = new Roo.CompositeElementLite([]);
9944 this.store = Roo.factory(this.store, Roo.data);
9945 this.setStore(this.store, true);
9948 if ( this.footer && this.footer.xtype) {
9950 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9952 this.footer.dataSource = this.store
9953 this.footer.container = fctr;
9954 this.footer = Roo.factory(this.footer, Roo);
9955 fctr.insertFirst(this.el);
9957 // this is a bit insane - as the paging toolbar seems to detach the el..
9958 // dom.parentNode.parentNode.parentNode
9959 // they get detached?
9963 Roo.View.superclass.constructor.call(this);
9968 Roo.extend(Roo.View, Roo.util.Observable, {
9971 * @cfg {Roo.data.Store} store Data store to load data from.
9976 * @cfg {String|Roo.Element} el The container element.
9981 * @cfg {String|Roo.Template} tpl The template used by this View
9985 * @cfg {String} dataName the named area of the template to use as the data area
9986 * Works with domtemplates roo-name="name"
9990 * @cfg {String} selectedClass The css class to add to selected nodes
9992 selectedClass : "x-view-selected",
9994 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9999 * @cfg {String} text to display on mask (default Loading)
10003 * @cfg {Boolean} multiSelect Allow multiple selection
10005 multiSelect : false,
10007 * @cfg {Boolean} singleSelect Allow single selection
10009 singleSelect: false,
10012 * @cfg {Boolean} toggleSelect - selecting
10014 toggleSelect : false,
10017 * Returns the element this view is bound to.
10018 * @return {Roo.Element}
10020 getEl : function(){
10021 return this.wrapEl;
10027 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10029 refresh : function(){
10030 Roo.log('refresh');
10033 // if we are using something like 'domtemplate', then
10034 // the what gets used is:
10035 // t.applySubtemplate(NAME, data, wrapping data..)
10036 // the outer template then get' applied with
10037 // the store 'extra data'
10038 // and the body get's added to the
10039 // roo-name="data" node?
10040 // <span class='roo-tpl-{name}'></span> ?????
10044 this.clearSelections();
10045 this.el.update("");
10047 var records = this.store.getRange();
10048 if(records.length < 1) {
10050 // is this valid?? = should it render a template??
10052 this.el.update(this.emptyText);
10056 if (this.dataName) {
10057 this.el.update(t.apply(this.store.meta)); //????
10058 el = this.el.child('.roo-tpl-' + this.dataName);
10061 for(var i = 0, len = records.length; i < len; i++){
10062 var data = this.prepareData(records[i].data, i, records[i]);
10063 this.fireEvent("preparedata", this, data, i, records[i]);
10064 html[html.length] = Roo.util.Format.trim(
10066 t.applySubtemplate(this.dataName, data, this.store.meta) :
10073 el.update(html.join(""));
10074 this.nodes = el.dom.childNodes;
10075 this.updateIndexes(0);
10080 * Function to override to reformat the data that is sent to
10081 * the template for each node.
10082 * DEPRICATED - use the preparedata event handler.
10083 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10084 * a JSON object for an UpdateManager bound view).
10086 prepareData : function(data, index, record)
10088 this.fireEvent("preparedata", this, data, index, record);
10092 onUpdate : function(ds, record){
10093 Roo.log('on update');
10094 this.clearSelections();
10095 var index = this.store.indexOf(record);
10096 var n = this.nodes[index];
10097 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10098 n.parentNode.removeChild(n);
10099 this.updateIndexes(index, index);
10105 onAdd : function(ds, records, index)
10107 Roo.log(['on Add', ds, records, index] );
10108 this.clearSelections();
10109 if(this.nodes.length == 0){
10113 var n = this.nodes[index];
10114 for(var i = 0, len = records.length; i < len; i++){
10115 var d = this.prepareData(records[i].data, i, records[i]);
10117 this.tpl.insertBefore(n, d);
10120 this.tpl.append(this.el, d);
10123 this.updateIndexes(index);
10126 onRemove : function(ds, record, index){
10127 Roo.log('onRemove');
10128 this.clearSelections();
10129 var el = this.dataName ?
10130 this.el.child('.roo-tpl-' + this.dataName) :
10133 el.dom.removeChild(this.nodes[index]);
10134 this.updateIndexes(index);
10138 * Refresh an individual node.
10139 * @param {Number} index
10141 refreshNode : function(index){
10142 this.onUpdate(this.store, this.store.getAt(index));
10145 updateIndexes : function(startIndex, endIndex){
10146 var ns = this.nodes;
10147 startIndex = startIndex || 0;
10148 endIndex = endIndex || ns.length - 1;
10149 for(var i = startIndex; i <= endIndex; i++){
10150 ns[i].nodeIndex = i;
10155 * Changes the data store this view uses and refresh the view.
10156 * @param {Store} store
10158 setStore : function(store, initial){
10159 if(!initial && this.store){
10160 this.store.un("datachanged", this.refresh);
10161 this.store.un("add", this.onAdd);
10162 this.store.un("remove", this.onRemove);
10163 this.store.un("update", this.onUpdate);
10164 this.store.un("clear", this.refresh);
10165 this.store.un("beforeload", this.onBeforeLoad);
10166 this.store.un("load", this.onLoad);
10167 this.store.un("loadexception", this.onLoad);
10171 store.on("datachanged", this.refresh, this);
10172 store.on("add", this.onAdd, this);
10173 store.on("remove", this.onRemove, this);
10174 store.on("update", this.onUpdate, this);
10175 store.on("clear", this.refresh, this);
10176 store.on("beforeload", this.onBeforeLoad, this);
10177 store.on("load", this.onLoad, this);
10178 store.on("loadexception", this.onLoad, this);
10186 * onbeforeLoad - masks the loading area.
10189 onBeforeLoad : function(store,opts)
10191 Roo.log('onBeforeLoad');
10193 this.el.update("");
10195 this.el.mask(this.mask ? this.mask : "Loading" );
10197 onLoad : function ()
10204 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10205 * @param {HTMLElement} node
10206 * @return {HTMLElement} The template node
10208 findItemFromChild : function(node){
10209 var el = this.dataName ?
10210 this.el.child('.roo-tpl-' + this.dataName,true) :
10213 if(!node || node.parentNode == el){
10216 var p = node.parentNode;
10217 while(p && p != el){
10218 if(p.parentNode == el){
10227 onClick : function(e){
10228 var item = this.findItemFromChild(e.getTarget());
10230 var index = this.indexOf(item);
10231 if(this.onItemClick(item, index, e) !== false){
10232 this.fireEvent("click", this, index, item, e);
10235 this.clearSelections();
10240 onContextMenu : function(e){
10241 var item = this.findItemFromChild(e.getTarget());
10243 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10248 onDblClick : function(e){
10249 var item = this.findItemFromChild(e.getTarget());
10251 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10255 onItemClick : function(item, index, e)
10257 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10260 if (this.toggleSelect) {
10261 var m = this.isSelected(item) ? 'unselect' : 'select';
10264 _t[m](item, true, false);
10267 if(this.multiSelect || this.singleSelect){
10268 if(this.multiSelect && e.shiftKey && this.lastSelection){
10269 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10271 this.select(item, this.multiSelect && e.ctrlKey);
10272 this.lastSelection = item;
10274 e.preventDefault();
10280 * Get the number of selected nodes.
10283 getSelectionCount : function(){
10284 return this.selections.length;
10288 * Get the currently selected nodes.
10289 * @return {Array} An array of HTMLElements
10291 getSelectedNodes : function(){
10292 return this.selections;
10296 * Get the indexes of the selected nodes.
10299 getSelectedIndexes : function(){
10300 var indexes = [], s = this.selections;
10301 for(var i = 0, len = s.length; i < len; i++){
10302 indexes.push(s[i].nodeIndex);
10308 * Clear all selections
10309 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10311 clearSelections : function(suppressEvent){
10312 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10313 this.cmp.elements = this.selections;
10314 this.cmp.removeClass(this.selectedClass);
10315 this.selections = [];
10316 if(!suppressEvent){
10317 this.fireEvent("selectionchange", this, this.selections);
10323 * Returns true if the passed node is selected
10324 * @param {HTMLElement/Number} node The node or node index
10325 * @return {Boolean}
10327 isSelected : function(node){
10328 var s = this.selections;
10332 node = this.getNode(node);
10333 return s.indexOf(node) !== -1;
10338 * @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
10339 * @param {Boolean} keepExisting (optional) true to keep existing selections
10340 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10342 select : function(nodeInfo, keepExisting, suppressEvent){
10343 if(nodeInfo instanceof Array){
10345 this.clearSelections(true);
10347 for(var i = 0, len = nodeInfo.length; i < len; i++){
10348 this.select(nodeInfo[i], true, true);
10352 var node = this.getNode(nodeInfo);
10353 if(!node || this.isSelected(node)){
10354 return; // already selected.
10357 this.clearSelections(true);
10359 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10360 Roo.fly(node).addClass(this.selectedClass);
10361 this.selections.push(node);
10362 if(!suppressEvent){
10363 this.fireEvent("selectionchange", this, this.selections);
10371 * @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
10372 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10373 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10375 unselect : function(nodeInfo, keepExisting, suppressEvent)
10377 if(nodeInfo instanceof Array){
10378 Roo.each(this.selections, function(s) {
10379 this.unselect(s, nodeInfo);
10383 var node = this.getNode(nodeInfo);
10384 if(!node || !this.isSelected(node)){
10385 Roo.log("not selected");
10386 return; // not selected.
10390 Roo.each(this.selections, function(s) {
10392 Roo.fly(node).removeClass(this.selectedClass);
10399 this.selections= ns;
10400 this.fireEvent("selectionchange", this, this.selections);
10404 * Gets a template node.
10405 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10406 * @return {HTMLElement} The node or null if it wasn't found
10408 getNode : function(nodeInfo){
10409 if(typeof nodeInfo == "string"){
10410 return document.getElementById(nodeInfo);
10411 }else if(typeof nodeInfo == "number"){
10412 return this.nodes[nodeInfo];
10418 * Gets a range template nodes.
10419 * @param {Number} startIndex
10420 * @param {Number} endIndex
10421 * @return {Array} An array of nodes
10423 getNodes : function(start, end){
10424 var ns = this.nodes;
10425 start = start || 0;
10426 end = typeof end == "undefined" ? ns.length - 1 : end;
10429 for(var i = start; i <= end; i++){
10433 for(var i = start; i >= end; i--){
10441 * Finds the index of the passed node
10442 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10443 * @return {Number} The index of the node or -1
10445 indexOf : function(node){
10446 node = this.getNode(node);
10447 if(typeof node.nodeIndex == "number"){
10448 return node.nodeIndex;
10450 var ns = this.nodes;
10451 for(var i = 0, len = ns.length; i < len; i++){
10462 * based on jquery fullcalendar
10466 Roo.bootstrap = Roo.bootstrap || {};
10468 * @class Roo.bootstrap.Calendar
10469 * @extends Roo.bootstrap.Component
10470 * Bootstrap Calendar class
10471 * @cfg {Boolean} loadMask (true|false) default false
10472 * @cfg {Object} header generate the user specific header of the calendar, default false
10475 * Create a new Container
10476 * @param {Object} config The config object
10481 Roo.bootstrap.Calendar = function(config){
10482 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10486 * Fires when a date is selected
10487 * @param {DatePicker} this
10488 * @param {Date} date The selected date
10492 * @event monthchange
10493 * Fires when the displayed month changes
10494 * @param {DatePicker} this
10495 * @param {Date} date The selected month
10497 'monthchange': true,
10499 * @event evententer
10500 * Fires when mouse over an event
10501 * @param {Calendar} this
10502 * @param {event} Event
10504 'evententer': true,
10506 * @event eventleave
10507 * Fires when the mouse leaves an
10508 * @param {Calendar} this
10511 'eventleave': true,
10513 * @event eventclick
10514 * Fires when the mouse click an
10515 * @param {Calendar} this
10524 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10527 * @cfg {Number} startDay
10528 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10536 getAutoCreate : function(){
10539 var fc_button = function(name, corner, style, content ) {
10540 return Roo.apply({},{
10542 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10544 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10547 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
10558 style : 'width:100%',
10565 cls : 'fc-header-left',
10567 fc_button('prev', 'left', 'arrow', '‹' ),
10568 fc_button('next', 'right', 'arrow', '›' ),
10569 { tag: 'span', cls: 'fc-header-space' },
10570 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
10578 cls : 'fc-header-center',
10582 cls: 'fc-header-title',
10585 html : 'month / year'
10593 cls : 'fc-header-right',
10595 /* fc_button('month', 'left', '', 'month' ),
10596 fc_button('week', '', '', 'week' ),
10597 fc_button('day', 'right', '', 'day' )
10609 header = this.header;
10612 var cal_heads = function() {
10614 // fixme - handle this.
10616 for (var i =0; i < Date.dayNames.length; i++) {
10617 var d = Date.dayNames[i];
10620 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
10621 html : d.substring(0,3)
10625 ret[0].cls += ' fc-first';
10626 ret[6].cls += ' fc-last';
10629 var cal_cell = function(n) {
10632 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10637 cls: 'fc-day-number',
10641 cls: 'fc-day-content',
10645 style: 'position: relative;' // height: 17px;
10657 var cal_rows = function() {
10660 for (var r = 0; r < 6; r++) {
10667 for (var i =0; i < Date.dayNames.length; i++) {
10668 var d = Date.dayNames[i];
10669 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10672 row.cn[0].cls+=' fc-first';
10673 row.cn[0].cn[0].style = 'min-height:90px';
10674 row.cn[6].cls+=' fc-last';
10678 ret[0].cls += ' fc-first';
10679 ret[4].cls += ' fc-prev-last';
10680 ret[5].cls += ' fc-last';
10687 cls: 'fc-border-separate',
10688 style : 'width:100%',
10696 cls : 'fc-first fc-last',
10714 cls : 'fc-content',
10715 style : "position: relative;",
10718 cls : 'fc-view fc-view-month fc-grid',
10719 style : 'position: relative',
10720 unselectable : 'on',
10723 cls : 'fc-event-container',
10724 style : 'position:absolute;z-index:8;top:0;left:0;'
10742 initEvents : function()
10745 throw "can not find store for calendar";
10751 style: "text-align:center",
10755 style: "background-color:white;width:50%;margin:250 auto",
10759 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10770 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10772 var size = this.el.select('.fc-content', true).first().getSize();
10773 this.maskEl.setSize(size.width, size.height);
10774 this.maskEl.enableDisplayMode("block");
10775 if(!this.loadMask){
10776 this.maskEl.hide();
10779 this.store = Roo.factory(this.store, Roo.data);
10780 this.store.on('load', this.onLoad, this);
10781 this.store.on('beforeload', this.onBeforeLoad, this);
10785 this.cells = this.el.select('.fc-day',true);
10786 //Roo.log(this.cells);
10787 this.textNodes = this.el.query('.fc-day-number');
10788 this.cells.addClassOnOver('fc-state-hover');
10790 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10791 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10792 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10793 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10795 this.on('monthchange', this.onMonthChange, this);
10797 this.update(new Date().clearTime());
10800 resize : function() {
10801 var sz = this.el.getSize();
10803 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10804 this.el.select('.fc-day-content div',true).setHeight(34);
10809 showPrevMonth : function(e){
10810 this.update(this.activeDate.add("mo", -1));
10812 showToday : function(e){
10813 this.update(new Date().clearTime());
10816 showNextMonth : function(e){
10817 this.update(this.activeDate.add("mo", 1));
10821 showPrevYear : function(){
10822 this.update(this.activeDate.add("y", -1));
10826 showNextYear : function(){
10827 this.update(this.activeDate.add("y", 1));
10832 update : function(date)
10834 var vd = this.activeDate;
10835 this.activeDate = date;
10836 // if(vd && this.el){
10837 // var t = date.getTime();
10838 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10839 // Roo.log('using add remove');
10841 // this.fireEvent('monthchange', this, date);
10843 // this.cells.removeClass("fc-state-highlight");
10844 // this.cells.each(function(c){
10845 // if(c.dateValue == t){
10846 // c.addClass("fc-state-highlight");
10847 // setTimeout(function(){
10848 // try{c.dom.firstChild.focus();}catch(e){}
10858 var days = date.getDaysInMonth();
10860 var firstOfMonth = date.getFirstDateOfMonth();
10861 var startingPos = firstOfMonth.getDay()-this.startDay;
10863 if(startingPos < this.startDay){
10867 var pm = date.add(Date.MONTH, -1);
10868 var prevStart = pm.getDaysInMonth()-startingPos;
10870 this.cells = this.el.select('.fc-day',true);
10871 this.textNodes = this.el.query('.fc-day-number');
10872 this.cells.addClassOnOver('fc-state-hover');
10874 var cells = this.cells.elements;
10875 var textEls = this.textNodes;
10877 Roo.each(cells, function(cell){
10878 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10881 days += startingPos;
10883 // convert everything to numbers so it's fast
10884 var day = 86400000;
10885 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10888 //Roo.log(prevStart);
10890 var today = new Date().clearTime().getTime();
10891 var sel = date.clearTime().getTime();
10892 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10893 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10894 var ddMatch = this.disabledDatesRE;
10895 var ddText = this.disabledDatesText;
10896 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10897 var ddaysText = this.disabledDaysText;
10898 var format = this.format;
10900 var setCellClass = function(cal, cell){
10902 //Roo.log('set Cell Class');
10904 var t = d.getTime();
10908 cell.dateValue = t;
10910 cell.className += " fc-today";
10911 cell.className += " fc-state-highlight";
10912 cell.title = cal.todayText;
10915 // disable highlight in other month..
10916 //cell.className += " fc-state-highlight";
10921 cell.className = " fc-state-disabled";
10922 cell.title = cal.minText;
10926 cell.className = " fc-state-disabled";
10927 cell.title = cal.maxText;
10931 if(ddays.indexOf(d.getDay()) != -1){
10932 cell.title = ddaysText;
10933 cell.className = " fc-state-disabled";
10936 if(ddMatch && format){
10937 var fvalue = d.dateFormat(format);
10938 if(ddMatch.test(fvalue)){
10939 cell.title = ddText.replace("%0", fvalue);
10940 cell.className = " fc-state-disabled";
10944 if (!cell.initialClassName) {
10945 cell.initialClassName = cell.dom.className;
10948 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10953 for(; i < startingPos; i++) {
10954 textEls[i].innerHTML = (++prevStart);
10955 d.setDate(d.getDate()+1);
10957 cells[i].className = "fc-past fc-other-month";
10958 setCellClass(this, cells[i]);
10963 for(; i < days; i++){
10964 intDay = i - startingPos + 1;
10965 textEls[i].innerHTML = (intDay);
10966 d.setDate(d.getDate()+1);
10968 cells[i].className = ''; // "x-date-active";
10969 setCellClass(this, cells[i]);
10973 for(; i < 42; i++) {
10974 textEls[i].innerHTML = (++extraDays);
10975 d.setDate(d.getDate()+1);
10977 cells[i].className = "fc-future fc-other-month";
10978 setCellClass(this, cells[i]);
10981 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10983 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10985 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10986 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10988 if(totalRows != 6){
10989 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10990 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10993 this.fireEvent('monthchange', this, date);
10997 if(!this.internalRender){
10998 var main = this.el.dom.firstChild;
10999 var w = main.offsetWidth;
11000 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11001 Roo.fly(main).setWidth(w);
11002 this.internalRender = true;
11003 // opera does not respect the auto grow header center column
11004 // then, after it gets a width opera refuses to recalculate
11005 // without a second pass
11006 if(Roo.isOpera && !this.secondPass){
11007 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11008 this.secondPass = true;
11009 this.update.defer(10, this, [date]);
11016 findCell : function(dt) {
11017 dt = dt.clearTime().getTime();
11019 this.cells.each(function(c){
11020 //Roo.log("check " +c.dateValue + '?=' + dt);
11021 if(c.dateValue == dt){
11031 findCells : function(ev) {
11032 var s = ev.start.clone().clearTime().getTime();
11034 var e= ev.end.clone().clearTime().getTime();
11037 this.cells.each(function(c){
11038 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11040 if(c.dateValue > e){
11043 if(c.dateValue < s){
11052 findBestRow: function(cells)
11056 for (var i =0 ; i < cells.length;i++) {
11057 ret = Math.max(cells[i].rows || 0,ret);
11064 addItem : function(ev)
11066 // look for vertical location slot in
11067 var cells = this.findCells(ev);
11069 ev.row = this.findBestRow(cells);
11071 // work out the location.
11075 for(var i =0; i < cells.length; i++) {
11083 if (crow.start.getY() == cells[i].getY()) {
11085 crow.end = cells[i];
11101 for (var i = 0; i < cells.length;i++) {
11102 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11106 this.calevents.push(ev);
11109 clearEvents: function() {
11111 if(!this.calevents){
11115 Roo.each(this.cells.elements, function(c){
11119 Roo.each(this.calevents, function(e) {
11120 Roo.each(e.els, function(el) {
11121 el.un('mouseenter' ,this.onEventEnter, this);
11122 el.un('mouseleave' ,this.onEventLeave, this);
11129 renderEvents: function()
11131 // first make sure there is enough space..
11133 this.cells.each(function(c) {
11135 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
11138 for (var e = 0; e < this.calevents.length; e++) {
11139 var ev = this.calevents[e];
11140 var cells = ev.cells;
11141 var rows = ev.rows;
11143 for(var i =0; i < rows.length; i++) {
11146 // how many rows should it span..
11149 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11150 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11152 unselectable : "on",
11155 cls: 'fc-event-inner',
11159 // cls: 'fc-event-time',
11160 // html : cells.length > 1 ? '' : ev.time
11164 cls: 'fc-event-title',
11165 html : String.format('{0}', ev.title)
11172 cls: 'ui-resizable-handle ui-resizable-e',
11173 html : '  '
11179 cfg.cls += ' fc-event-start';
11181 if ((i+1) == rows.length) {
11182 cfg.cls += ' fc-event-end';
11185 var ctr = this.el.select('.fc-event-container',true).first();
11186 var cg = ctr.createChild(cfg);
11188 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11189 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11190 cg.on('click', this.onEventClick, this, ev);
11194 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11195 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11197 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11198 cg.setWidth(ebox.right - sbox.x -2);
11206 onEventEnter: function (e, el,event,d) {
11207 this.fireEvent('evententer', this, el, event);
11210 onEventLeave: function (e, el,event,d) {
11211 this.fireEvent('eventleave', this, el, event);
11214 onEventClick: function (e, el,event,d) {
11215 this.fireEvent('eventclick', this, el, event);
11218 onMonthChange: function () {
11222 onLoad: function ()
11224 this.calevents = [];
11227 if(this.store.getCount() > 0){
11228 this.store.data.each(function(d){
11231 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11232 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11233 time : d.data.start_time,
11234 title : d.data.title,
11235 description : d.data.description,
11236 venue : d.data.venue
11241 this.renderEvents();
11244 this.maskEl.hide();
11248 onBeforeLoad: function()
11250 this.clearEvents();
11253 this.maskEl.show();
11267 * @class Roo.bootstrap.Popover
11268 * @extends Roo.bootstrap.Component
11269 * Bootstrap Popover class
11270 * @cfg {String} html contents of the popover (or false to use children..)
11271 * @cfg {String} title of popover (or false to hide)
11272 * @cfg {String} placement how it is placed
11273 * @cfg {String} trigger click || hover (or false to trigger manually)
11274 * @cfg {String} over what (parent or false to trigger manually.)
11277 * Create a new Popover
11278 * @param {Object} config The config object
11281 Roo.bootstrap.Popover = function(config){
11282 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11285 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11287 title: 'Fill in a title',
11290 placement : 'right',
11291 trigger : 'hover', // hover
11295 can_build_overlaid : false,
11297 getChildContainer : function()
11299 return this.el.select('.popover-content',true).first();
11302 getAutoCreate : function(){
11303 Roo.log('make popover?');
11305 cls : 'popover roo-dynamic',
11306 style: 'display:block',
11312 cls : 'popover-inner',
11316 cls: 'popover-title',
11320 cls : 'popover-content',
11331 setTitle: function(str)
11333 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11335 setContent: function(str)
11337 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11339 // as it get's added to the bottom of the page.
11340 onRender : function(ct, position)
11342 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11344 var cfg = Roo.apply({}, this.getAutoCreate());
11348 cfg.cls += ' ' + this.cls;
11351 cfg.style = this.style;
11353 Roo.log("adding to ")
11354 this.el = Roo.get(document.body).createChild(cfg, position);
11360 initEvents : function()
11362 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11363 this.el.enableDisplayMode('block');
11365 if (this.over === false) {
11368 if (this.triggers === false) {
11371 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11372 var triggers = this.trigger ? this.trigger.split(' ') : [];
11373 Roo.each(triggers, function(trigger) {
11375 if (trigger == 'click') {
11376 on_el.on('click', this.toggle, this);
11377 } else if (trigger != 'manual') {
11378 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11379 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11381 on_el.on(eventIn ,this.enter, this);
11382 on_el.on(eventOut, this.leave, this);
11393 toggle : function () {
11394 this.hoverState == 'in' ? this.leave() : this.enter();
11397 enter : function () {
11400 clearTimeout(this.timeout);
11402 this.hoverState = 'in'
11404 if (!this.delay || !this.delay.show) {
11409 this.timeout = setTimeout(function () {
11410 if (_t.hoverState == 'in') {
11413 }, this.delay.show)
11415 leave : function() {
11416 clearTimeout(this.timeout);
11418 this.hoverState = 'out'
11420 if (!this.delay || !this.delay.hide) {
11425 this.timeout = setTimeout(function () {
11426 if (_t.hoverState == 'out') {
11429 }, this.delay.hide)
11432 show : function (on_el)
11435 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11438 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11439 if (this.html !== false) {
11440 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11442 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11443 if (!this.title.length) {
11444 this.el.select('.popover-title',true).hide();
11447 var placement = typeof this.placement == 'function' ?
11448 this.placement.call(this, this.el, on_el) :
11451 var autoToken = /\s?auto?\s?/i;
11452 var autoPlace = autoToken.test(placement);
11454 placement = placement.replace(autoToken, '') || 'top';
11458 //this.el.setXY([0,0]);
11460 this.el.dom.style.display='block';
11461 this.el.addClass(placement);
11463 //this.el.appendTo(on_el);
11465 var p = this.getPosition();
11466 var box = this.el.getBox();
11471 var align = Roo.bootstrap.Popover.alignment[placement]
11472 this.el.alignTo(on_el, align[0],align[1]);
11473 //var arrow = this.el.select('.arrow',true).first();
11474 //arrow.set(align[2],
11476 this.el.addClass('in');
11477 this.hoverState = null;
11479 if (this.el.hasClass('fade')) {
11486 this.el.setXY([0,0]);
11487 this.el.removeClass('in');
11494 Roo.bootstrap.Popover.alignment = {
11495 'left' : ['r-l', [-10,0], 'right'],
11496 'right' : ['l-r', [10,0], 'left'],
11497 'bottom' : ['t-b', [0,10], 'top'],
11498 'top' : [ 'b-t', [0,-10], 'bottom']
11509 * @class Roo.bootstrap.Progress
11510 * @extends Roo.bootstrap.Component
11511 * Bootstrap Progress class
11512 * @cfg {Boolean} striped striped of the progress bar
11513 * @cfg {Boolean} active animated of the progress bar
11517 * Create a new Progress
11518 * @param {Object} config The config object
11521 Roo.bootstrap.Progress = function(config){
11522 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
11525 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
11530 getAutoCreate : function(){
11538 cfg.cls += ' progress-striped';
11542 cfg.cls += ' active';
11561 * @class Roo.bootstrap.ProgressBar
11562 * @extends Roo.bootstrap.Component
11563 * Bootstrap ProgressBar class
11564 * @cfg {Number} aria_valuenow aria-value now
11565 * @cfg {Number} aria_valuemin aria-value min
11566 * @cfg {Number} aria_valuemax aria-value max
11567 * @cfg {String} label label for the progress bar
11568 * @cfg {String} panel (success | info | warning | danger )
11569 * @cfg {String} role role of the progress bar
11570 * @cfg {String} sr_only text
11574 * Create a new ProgressBar
11575 * @param {Object} config The config object
11578 Roo.bootstrap.ProgressBar = function(config){
11579 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
11582 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
11586 aria_valuemax : 100,
11592 getAutoCreate : function()
11597 cls: 'progress-bar',
11598 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
11610 cfg.role = this.role;
11613 if(this.aria_valuenow){
11614 cfg['aria-valuenow'] = this.aria_valuenow;
11617 if(this.aria_valuemin){
11618 cfg['aria-valuemin'] = this.aria_valuemin;
11621 if(this.aria_valuemax){
11622 cfg['aria-valuemax'] = this.aria_valuemax;
11625 if(this.label && !this.sr_only){
11626 cfg.html = this.label;
11630 cfg.cls += ' progress-bar-' + this.panel;
11636 update : function(aria_valuenow)
11638 this.aria_valuenow = aria_valuenow;
11640 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11655 * @class Roo.bootstrap.TabPanel
11656 * @extends Roo.bootstrap.Component
11657 * Bootstrap TabPanel class
11658 * @cfg {Boolean} active panel active
11659 * @cfg {String} html panel content
11660 * @cfg {String} tabId tab relate id
11661 * @cfg {String} navId The navbar which triggers show hide
11665 * Create a new TabPanel
11666 * @param {Object} config The config object
11669 Roo.bootstrap.TabPanel = function(config){
11670 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11674 * Fires when the active status changes
11675 * @param {Roo.bootstrap.TabPanel} this
11676 * @param {Boolean} state the new state
11683 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11690 getAutoCreate : function(){
11694 html: this.html || ''
11698 cfg.cls += ' active';
11702 cfg.tabId = this.tabId;
11707 onRender : function(ct, position)
11709 // Roo.log("Call onRender: " + this.xtype);
11711 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11713 if (this.navId && this.tabId) {
11714 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11716 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11718 item.on('changed', function(item, state) {
11719 this.setActive(state);
11725 setActive: function(state)
11727 Roo.log("panel - set active " + this.tabId + "=" + state);
11729 this.active = state;
11731 this.el.removeClass('active');
11733 } else if (!this.el.hasClass('active')) {
11734 this.el.addClass('active');
11736 this.fireEvent('changed', this, state);
11753 * @class Roo.bootstrap.DateField
11754 * @extends Roo.bootstrap.Input
11755 * Bootstrap DateField class
11756 * @cfg {Number} weekStart default 0
11757 * @cfg {Number} weekStart default 0
11758 * @cfg {Number} viewMode default empty, (months|years)
11759 * @cfg {Number} minViewMode default empty, (months|years)
11760 * @cfg {Number} startDate default -Infinity
11761 * @cfg {Number} endDate default Infinity
11762 * @cfg {Boolean} todayHighlight default false
11763 * @cfg {Boolean} todayBtn default false
11764 * @cfg {Boolean} calendarWeeks default false
11765 * @cfg {Object} daysOfWeekDisabled default empty
11767 * @cfg {Boolean} keyboardNavigation default true
11768 * @cfg {String} language default en
11771 * Create a new DateField
11772 * @param {Object} config The config object
11775 Roo.bootstrap.DateField = function(config){
11776 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
11780 * Fires when this field show.
11781 * @param {Roo.bootstrap.DateField} this
11782 * @param {Mixed} date The date value
11787 * Fires when this field hide.
11788 * @param {Roo.bootstrap.DateField} this
11789 * @param {Mixed} date The date value
11794 * Fires when select a date.
11795 * @param {Roo.bootstrap.DateField} this
11796 * @param {Mixed} date The date value
11802 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11805 * @cfg {String} format
11806 * The default date format string which can be overriden for localization support. The format must be
11807 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11811 * @cfg {String} altFormats
11812 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11813 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11815 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11823 todayHighlight : false,
11829 keyboardNavigation: true,
11831 calendarWeeks: false,
11833 startDate: -Infinity,
11837 daysOfWeekDisabled: [],
11841 UTCDate: function()
11843 return new Date(Date.UTC.apply(Date, arguments));
11846 UTCToday: function()
11848 var today = new Date();
11849 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11852 getDate: function() {
11853 var d = this.getUTCDate();
11854 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11857 getUTCDate: function() {
11861 setDate: function(d) {
11862 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11865 setUTCDate: function(d) {
11867 this.setValue(this.formatDate(this.date));
11870 onRender: function(ct, position)
11873 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11875 this.language = this.language || 'en';
11876 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11877 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11879 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11880 this.format = this.format || 'm/d/y';
11881 this.isInline = false;
11882 this.isInput = true;
11883 this.component = this.el.select('.add-on', true).first() || false;
11884 this.component = (this.component && this.component.length === 0) ? false : this.component;
11885 this.hasInput = this.component && this.inputEL().length;
11887 if (typeof(this.minViewMode === 'string')) {
11888 switch (this.minViewMode) {
11890 this.minViewMode = 1;
11893 this.minViewMode = 2;
11896 this.minViewMode = 0;
11901 if (typeof(this.viewMode === 'string')) {
11902 switch (this.viewMode) {
11915 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11917 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11919 this.picker().on('mousedown', this.onMousedown, this);
11920 this.picker().on('click', this.onClick, this);
11922 this.picker().addClass('datepicker-dropdown');
11924 this.startViewMode = this.viewMode;
11927 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11928 if(!this.calendarWeeks){
11933 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11934 v.attr('colspan', function(i, val){
11935 return parseInt(val) + 1;
11940 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11942 this.setStartDate(this.startDate);
11943 this.setEndDate(this.endDate);
11945 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11952 if(this.isInline) {
11957 picker : function()
11959 return this.el.select('.datepicker', true).first();
11962 fillDow: function()
11964 var dowCnt = this.weekStart;
11973 if(this.calendarWeeks){
11981 while (dowCnt < this.weekStart + 7) {
11985 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11989 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11992 fillMonths: function()
11995 var months = this.picker().select('>.datepicker-months td', true).first();
11997 months.dom.innerHTML = '';
12003 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12006 months.createChild(month);
12011 update: function(){
12013 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12015 if (this.date < this.startDate) {
12016 this.viewDate = new Date(this.startDate);
12017 } else if (this.date > this.endDate) {
12018 this.viewDate = new Date(this.endDate);
12020 this.viewDate = new Date(this.date);
12027 var d = new Date(this.viewDate),
12028 year = d.getUTCFullYear(),
12029 month = d.getUTCMonth(),
12030 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12031 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12032 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12033 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12034 currentDate = this.date && this.date.valueOf(),
12035 today = this.UTCToday();
12037 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12039 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12041 // this.picker.select('>tfoot th.today').
12042 // .text(dates[this.language].today)
12043 // .toggle(this.todayBtn !== false);
12045 this.updateNavArrows();
12048 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12050 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12052 prevMonth.setUTCDate(day);
12054 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12056 var nextMonth = new Date(prevMonth);
12058 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12060 nextMonth = nextMonth.valueOf();
12062 var fillMonths = false;
12064 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12066 while(prevMonth.valueOf() < nextMonth) {
12069 if (prevMonth.getUTCDay() === this.weekStart) {
12071 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12079 if(this.calendarWeeks){
12080 // ISO 8601: First week contains first thursday.
12081 // ISO also states week starts on Monday, but we can be more abstract here.
12083 // Start of current week: based on weekstart/current date
12084 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12085 // Thursday of this week
12086 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12087 // First Thursday of year, year from thursday
12088 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12089 // Calendar week: ms between thursdays, div ms per day, div 7 days
12090 calWeek = (th - yth) / 864e5 / 7 + 1;
12092 fillMonths.cn.push({
12100 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12102 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12105 if (this.todayHighlight &&
12106 prevMonth.getUTCFullYear() == today.getFullYear() &&
12107 prevMonth.getUTCMonth() == today.getMonth() &&
12108 prevMonth.getUTCDate() == today.getDate()) {
12109 clsName += ' today';
12112 if (currentDate && prevMonth.valueOf() === currentDate) {
12113 clsName += ' active';
12116 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12117 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12118 clsName += ' disabled';
12121 fillMonths.cn.push({
12123 cls: 'day ' + clsName,
12124 html: prevMonth.getDate()
12127 prevMonth.setDate(prevMonth.getDate()+1);
12130 var currentYear = this.date && this.date.getUTCFullYear();
12131 var currentMonth = this.date && this.date.getUTCMonth();
12133 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12135 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12136 v.removeClass('active');
12138 if(currentYear === year && k === currentMonth){
12139 v.addClass('active');
12142 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12143 v.addClass('disabled');
12149 year = parseInt(year/10, 10) * 10;
12151 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12153 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12156 for (var i = -1; i < 11; i++) {
12157 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12159 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12167 showMode: function(dir) {
12169 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12171 Roo.each(this.picker().select('>div',true).elements, function(v){
12172 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12175 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12180 if(this.isInline) return;
12182 this.picker().removeClass(['bottom', 'top']);
12184 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12186 * place to the top of element!
12190 this.picker().addClass('top');
12191 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12196 this.picker().addClass('bottom');
12198 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12201 parseDate : function(value){
12202 if(!value || value instanceof Date){
12205 var v = Date.parseDate(value, this.format);
12206 if (!v && this.useIso) {
12207 v = Date.parseDate(value, 'Y-m-d');
12209 if(!v && this.altFormats){
12210 if(!this.altFormatsArray){
12211 this.altFormatsArray = this.altFormats.split("|");
12213 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12214 v = Date.parseDate(value, this.altFormatsArray[i]);
12220 formatDate : function(date, fmt){
12221 return (!date || !(date instanceof Date)) ?
12222 date : date.dateFormat(fmt || this.format);
12225 onFocus : function()
12227 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12231 onBlur : function()
12233 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12239 this.picker().show();
12243 this.fireEvent('show', this, this.date);
12248 if(this.isInline) return;
12249 this.picker().hide();
12250 this.viewMode = this.startViewMode;
12253 this.fireEvent('hide', this, this.date);
12257 onMousedown: function(e){
12258 e.stopPropagation();
12259 e.preventDefault();
12262 keyup: function(e){
12263 Roo.bootstrap.DateField.superclass.keyup.call(this);
12268 setValue: function(v){
12269 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12271 this.fireEvent('select', this, this.date);
12275 fireKey: function(e){
12276 if (!this.picker().isVisible()){
12277 if (e.keyCode == 27) // allow escape to hide and re-show picker
12281 var dateChanged = false,
12283 newDate, newViewDate;
12287 e.preventDefault();
12291 if (!this.keyboardNavigation) break;
12292 dir = e.keyCode == 37 ? -1 : 1;
12295 newDate = this.moveYear(this.date, dir);
12296 newViewDate = this.moveYear(this.viewDate, dir);
12297 } else if (e.shiftKey){
12298 newDate = this.moveMonth(this.date, dir);
12299 newViewDate = this.moveMonth(this.viewDate, dir);
12301 newDate = new Date(this.date);
12302 newDate.setUTCDate(this.date.getUTCDate() + dir);
12303 newViewDate = new Date(this.viewDate);
12304 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12306 if (this.dateWithinRange(newDate)){
12307 this.date = newDate;
12308 this.viewDate = newViewDate;
12309 this.setValue(this.formatDate(this.date));
12311 e.preventDefault();
12312 dateChanged = true;
12317 if (!this.keyboardNavigation) break;
12318 dir = e.keyCode == 38 ? -1 : 1;
12320 newDate = this.moveYear(this.date, dir);
12321 newViewDate = this.moveYear(this.viewDate, dir);
12322 } else if (e.shiftKey){
12323 newDate = this.moveMonth(this.date, dir);
12324 newViewDate = this.moveMonth(this.viewDate, dir);
12326 newDate = new Date(this.date);
12327 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12328 newViewDate = new Date(this.viewDate);
12329 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12331 if (this.dateWithinRange(newDate)){
12332 this.date = newDate;
12333 this.viewDate = newViewDate;
12334 this.setValue(this.formatDate(this.date));
12336 e.preventDefault();
12337 dateChanged = true;
12341 this.setValue(this.formatDate(this.date));
12343 e.preventDefault();
12346 this.setValue(this.formatDate(this.date));
12353 onClick: function(e) {
12354 e.stopPropagation();
12355 e.preventDefault();
12357 var target = e.getTarget();
12359 if(target.nodeName.toLowerCase() === 'i'){
12360 target = Roo.get(target).dom.parentNode;
12363 var nodeName = target.nodeName;
12364 var className = target.className;
12365 var html = target.innerHTML;
12367 switch(nodeName.toLowerCase()) {
12369 switch(className) {
12375 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12376 switch(this.viewMode){
12378 this.viewDate = this.moveMonth(this.viewDate, dir);
12382 this.viewDate = this.moveYear(this.viewDate, dir);
12388 var date = new Date();
12389 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12391 this.setValue(this.formatDate(this.date));
12397 if (className.indexOf('disabled') === -1) {
12398 this.viewDate.setUTCDate(1);
12399 if (className.indexOf('month') !== -1) {
12400 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12402 var year = parseInt(html, 10) || 0;
12403 this.viewDate.setUTCFullYear(year);
12412 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12413 var day = parseInt(html, 10) || 1;
12414 var year = this.viewDate.getUTCFullYear(),
12415 month = this.viewDate.getUTCMonth();
12417 if (className.indexOf('old') !== -1) {
12424 } else if (className.indexOf('new') !== -1) {
12432 this.date = this.UTCDate(year, month, day,0,0,0,0);
12433 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12435 this.setValue(this.formatDate(this.date));
12442 setStartDate: function(startDate){
12443 this.startDate = startDate || -Infinity;
12444 if (this.startDate !== -Infinity) {
12445 this.startDate = this.parseDate(this.startDate);
12448 this.updateNavArrows();
12451 setEndDate: function(endDate){
12452 this.endDate = endDate || Infinity;
12453 if (this.endDate !== Infinity) {
12454 this.endDate = this.parseDate(this.endDate);
12457 this.updateNavArrows();
12460 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
12461 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
12462 if (typeof(this.daysOfWeekDisabled) !== 'object') {
12463 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
12465 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
12466 return parseInt(d, 10);
12469 this.updateNavArrows();
12472 updateNavArrows: function() {
12473 var d = new Date(this.viewDate),
12474 year = d.getUTCFullYear(),
12475 month = d.getUTCMonth();
12477 Roo.each(this.picker().select('.prev', true).elements, function(v){
12479 switch (this.viewMode) {
12482 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
12488 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
12495 Roo.each(this.picker().select('.next', true).elements, function(v){
12497 switch (this.viewMode) {
12500 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
12506 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
12514 moveMonth: function(date, dir){
12515 if (!dir) return date;
12516 var new_date = new Date(date.valueOf()),
12517 day = new_date.getUTCDate(),
12518 month = new_date.getUTCMonth(),
12519 mag = Math.abs(dir),
12521 dir = dir > 0 ? 1 : -1;
12524 // If going back one month, make sure month is not current month
12525 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
12527 return new_date.getUTCMonth() == month;
12529 // If going forward one month, make sure month is as expected
12530 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
12532 return new_date.getUTCMonth() != new_month;
12534 new_month = month + dir;
12535 new_date.setUTCMonth(new_month);
12536 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
12537 if (new_month < 0 || new_month > 11)
12538 new_month = (new_month + 12) % 12;
12540 // For magnitudes >1, move one month at a time...
12541 for (var i=0; i<mag; i++)
12542 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
12543 new_date = this.moveMonth(new_date, dir);
12544 // ...then reset the day, keeping it in the new month
12545 new_month = new_date.getUTCMonth();
12546 new_date.setUTCDate(day);
12548 return new_month != new_date.getUTCMonth();
12551 // Common date-resetting loop -- if date is beyond end of month, make it
12554 new_date.setUTCDate(--day);
12555 new_date.setUTCMonth(new_month);
12560 moveYear: function(date, dir){
12561 return this.moveMonth(date, dir*12);
12564 dateWithinRange: function(date){
12565 return date >= this.startDate && date <= this.endDate;
12569 remove: function() {
12570 this.picker().remove();
12575 Roo.apply(Roo.bootstrap.DateField, {
12586 html: '<i class="icon-arrow-left"/>'
12596 html: '<i class="icon-arrow-right"/>'
12638 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12639 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12640 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12641 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12642 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12655 navFnc: 'FullYear',
12660 navFnc: 'FullYear',
12665 Roo.apply(Roo.bootstrap.DateField, {
12669 cls: 'datepicker dropdown-menu',
12673 cls: 'datepicker-days',
12677 cls: 'table-condensed',
12679 Roo.bootstrap.DateField.head,
12683 Roo.bootstrap.DateField.footer
12690 cls: 'datepicker-months',
12694 cls: 'table-condensed',
12696 Roo.bootstrap.DateField.head,
12697 Roo.bootstrap.DateField.content,
12698 Roo.bootstrap.DateField.footer
12705 cls: 'datepicker-years',
12709 cls: 'table-condensed',
12711 Roo.bootstrap.DateField.head,
12712 Roo.bootstrap.DateField.content,
12713 Roo.bootstrap.DateField.footer
12732 * @class Roo.bootstrap.TimeField
12733 * @extends Roo.bootstrap.Input
12734 * Bootstrap DateField class
12738 * Create a new TimeField
12739 * @param {Object} config The config object
12742 Roo.bootstrap.TimeField = function(config){
12743 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12747 * Fires when this field show.
12748 * @param {Roo.bootstrap.DateField} this
12749 * @param {Mixed} date The date value
12754 * Fires when this field hide.
12755 * @param {Roo.bootstrap.DateField} this
12756 * @param {Mixed} date The date value
12761 * Fires when select a date.
12762 * @param {Roo.bootstrap.DateField} this
12763 * @param {Mixed} date The date value
12769 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
12772 * @cfg {String} format
12773 * The default time format string which can be overriden for localization support. The format must be
12774 * valid according to {@link Date#parseDate} (defaults to 'H:i').
12778 onRender: function(ct, position)
12781 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
12783 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
12785 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12787 this.pop = this.picker().select('>.datepicker-time',true).first();
12788 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12790 this.picker().on('mousedown', this.onMousedown, this);
12791 this.picker().on('click', this.onClick, this);
12793 this.picker().addClass('datepicker-dropdown');
12798 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12799 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12800 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12801 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12802 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12803 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12807 fireKey: function(e){
12808 if (!this.picker().isVisible()){
12809 if (e.keyCode == 27) // allow escape to hide and re-show picker
12814 e.preventDefault();
12822 this.onTogglePeriod();
12825 this.onIncrementMinutes();
12828 this.onDecrementMinutes();
12837 onClick: function(e) {
12838 e.stopPropagation();
12839 e.preventDefault();
12842 picker : function()
12844 return this.el.select('.datepicker', true).first();
12847 fillTime: function()
12849 var time = this.pop.select('tbody', true).first();
12851 time.dom.innerHTML = '';
12866 cls: 'hours-up glyphicon glyphicon-chevron-up'
12886 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12907 cls: 'timepicker-hour',
12922 cls: 'timepicker-minute',
12937 cls: 'btn btn-primary period',
12959 cls: 'hours-down glyphicon glyphicon-chevron-down'
12979 cls: 'minutes-down glyphicon glyphicon-chevron-down'
12997 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13004 var hours = this.time.getHours();
13005 var minutes = this.time.getMinutes();
13018 hours = hours - 12;
13022 hours = '0' + hours;
13026 minutes = '0' + minutes;
13029 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13030 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13031 this.pop.select('button', true).first().dom.innerHTML = period;
13037 this.picker().removeClass(['bottom', 'top']);
13039 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13041 * place to the top of element!
13045 this.picker().addClass('top');
13046 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13051 this.picker().addClass('bottom');
13053 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13056 onFocus : function()
13058 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13062 onBlur : function()
13064 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13070 this.picker().show();
13075 this.fireEvent('show', this, this.date);
13080 this.picker().hide();
13083 this.fireEvent('hide', this, this.date);
13086 setTime : function()
13089 this.setValue(this.time.format(this.format));
13091 this.fireEvent('select', this, this.date);
13096 onMousedown: function(e){
13097 e.stopPropagation();
13098 e.preventDefault();
13101 onIncrementHours: function()
13103 Roo.log('onIncrementHours');
13104 this.time = this.time.add(Date.HOUR, 1);
13109 onDecrementHours: function()
13111 Roo.log('onDecrementHours');
13112 this.time = this.time.add(Date.HOUR, -1);
13116 onIncrementMinutes: function()
13118 Roo.log('onIncrementMinutes');
13119 this.time = this.time.add(Date.MINUTE, 1);
13123 onDecrementMinutes: function()
13125 Roo.log('onDecrementMinutes');
13126 this.time = this.time.add(Date.MINUTE, -1);
13130 onTogglePeriod: function()
13132 Roo.log('onTogglePeriod');
13133 this.time = this.time.add(Date.HOUR, 12);
13140 Roo.apply(Roo.bootstrap.TimeField, {
13170 cls: 'btn btn-info ok',
13182 Roo.apply(Roo.bootstrap.TimeField, {
13186 cls: 'datepicker dropdown-menu',
13190 cls: 'datepicker-time',
13194 cls: 'table-condensed',
13196 Roo.bootstrap.TimeField.content,
13197 Roo.bootstrap.TimeField.footer
13216 * @class Roo.bootstrap.CheckBox
13217 * @extends Roo.bootstrap.Input
13218 * Bootstrap CheckBox class
13220 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13221 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13222 * @cfg {String} boxLabel The text that appears beside the checkbox
13223 * @cfg {Boolean} checked initnal the element
13226 * Create a new CheckBox
13227 * @param {Object} config The config object
13230 Roo.bootstrap.CheckBox = function(config){
13231 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13236 * Fires when the element is checked or unchecked.
13237 * @param {Roo.bootstrap.CheckBox} this This input
13238 * @param {Boolean} checked The new checked value
13244 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13246 inputType: 'checkbox',
13252 getAutoCreate : function()
13254 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13260 cfg.cls = 'form-group' //input-group
13265 type : this.inputType,
13266 value : (!this.checked) ? this.valueOff : this.inputValue,
13268 placeholder : this.placeholder || ''
13272 if (this.disabled) {
13273 input.disabled=true;
13277 input.checked = this.checked;
13281 input.name = this.name;
13285 input.cls += ' input-' + this.size;
13289 ['xs','sm','md','lg'].map(function(size){
13290 if (settings[size]) {
13291 cfg.cls += ' col-' + size + '-' + settings[size];
13295 var inputblock = input;
13297 if (this.before || this.after) {
13300 cls : 'input-group',
13304 inputblock.cn.push({
13306 cls : 'input-group-addon',
13310 inputblock.cn.push(input);
13312 inputblock.cn.push({
13314 cls : 'input-group-addon',
13321 if (align ==='left' && this.fieldLabel.length) {
13322 Roo.log("left and has label");
13328 cls : 'control-label col-md-' + this.labelWidth,
13329 html : this.fieldLabel
13333 cls : "col-md-" + (12 - this.labelWidth),
13340 } else if ( this.fieldLabel.length) {
13345 tag: this.boxLabel ? 'span' : 'label',
13347 cls: 'control-label box-input-label',
13348 //cls : 'input-group-addon',
13349 html : this.fieldLabel
13359 Roo.log(" no label && no align");
13374 html: this.boxLabel
13383 * return the real input element.
13385 inputEl: function ()
13387 return this.el.select('input.form-box',true).first();
13390 initEvents : function()
13392 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13394 this.inputEl().on('click', this.onClick, this);
13398 onClick : function()
13400 this.setChecked(!this.checked);
13403 setChecked : function(state,suppressEvent)
13405 this.checked = state;
13407 this.inputEl().dom.checked = state;
13409 if(suppressEvent !== true){
13410 this.fireEvent('check', this, state);
13413 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13417 setValue : function(v,suppressEvent)
13419 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
13433 * @class Roo.bootstrap.Radio
13434 * @extends Roo.bootstrap.CheckBox
13435 * Bootstrap Radio class
13438 * Create a new Radio
13439 * @param {Object} config The config object
13442 Roo.bootstrap.Radio = function(config){
13443 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
13447 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
13449 inputType: 'radio',
13453 getAutoCreate : function()
13455 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13461 cfg.cls = 'form-group' //input-group
13466 type : this.inputType,
13467 value : (!this.checked) ? this.valueOff : this.inputValue,
13469 placeholder : this.placeholder || ''
13473 if (this.disabled) {
13474 input.disabled=true;
13478 input.checked = this.checked;
13482 input.name = this.name;
13486 input.cls += ' input-' + this.size;
13490 ['xs','sm','md','lg'].map(function(size){
13491 if (settings[size]) {
13492 cfg.cls += ' col-' + size + '-' + settings[size];
13496 var inputblock = input;
13498 if (this.before || this.after) {
13501 cls : 'input-group',
13505 inputblock.cn.push({
13507 cls : 'input-group-addon',
13511 inputblock.cn.push(input);
13513 inputblock.cn.push({
13515 cls : 'input-group-addon',
13522 if (align ==='left' && this.fieldLabel.length) {
13523 Roo.log("left and has label");
13529 cls : 'control-label col-md-' + this.labelWidth,
13530 html : this.fieldLabel
13534 cls : "col-md-" + (12 - this.labelWidth),
13541 } else if ( this.fieldLabel.length) {
13548 cls: 'control-label box-input-label',
13549 //cls : 'input-group-addon',
13550 html : this.fieldLabel
13560 Roo.log(" no label && no align");
13575 html: this.boxLabel
13583 onClick : function()
13585 this.setChecked(true);
13588 setChecked : function(state,suppressEvent)
13591 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13592 v.dom.checked = false;
13596 this.checked = state;
13597 this.inputEl().dom.checked = state;
13599 if(suppressEvent !== true){
13600 this.fireEvent('check', this, state);
13603 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13607 getGroupValue : function()
13610 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13611 if(v.dom.checked == true){
13612 value = v.dom.value;
13620 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
13621 * @return {Mixed} value The field value
13623 getValue : function(){
13624 return this.getGroupValue();
13630 //<script type="text/javascript">
13633 * Based Ext JS Library 1.1.1
13634 * Copyright(c) 2006-2007, Ext JS, LLC.
13640 * @class Roo.HtmlEditorCore
13641 * @extends Roo.Component
13642 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13644 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13647 Roo.HtmlEditorCore = function(config){
13650 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13653 * @event initialize
13654 * Fires when the editor is fully initialized (including the iframe)
13655 * @param {Roo.HtmlEditorCore} this
13660 * Fires when the editor is first receives the focus. Any insertion must wait
13661 * until after this event.
13662 * @param {Roo.HtmlEditorCore} this
13666 * @event beforesync
13667 * Fires before the textarea is updated with content from the editor iframe. Return false
13668 * to cancel the sync.
13669 * @param {Roo.HtmlEditorCore} this
13670 * @param {String} html
13674 * @event beforepush
13675 * Fires before the iframe editor is updated with content from the textarea. Return false
13676 * to cancel the push.
13677 * @param {Roo.HtmlEditorCore} this
13678 * @param {String} html
13683 * Fires when the textarea is updated with content from the editor iframe.
13684 * @param {Roo.HtmlEditorCore} this
13685 * @param {String} html
13690 * Fires when the iframe editor is updated with content from the textarea.
13691 * @param {Roo.HtmlEditorCore} this
13692 * @param {String} html
13697 * @event editorevent
13698 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13699 * @param {Roo.HtmlEditorCore} this
13707 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13711 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13717 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13722 * @cfg {Number} height (in pixels)
13726 * @cfg {Number} width (in pixels)
13731 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13734 stylesheets: false,
13739 // private properties
13740 validationEvent : false,
13742 initialized : false,
13744 sourceEditMode : false,
13745 onFocus : Roo.emptyFn,
13747 hideMode:'offsets',
13755 * Protected method that will not generally be called directly. It
13756 * is called when the editor initializes the iframe with HTML contents. Override this method if you
13757 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
13759 getDocMarkup : function(){
13762 Roo.log(this.stylesheets);
13764 // inherit styels from page...??
13765 if (this.stylesheets === false) {
13767 Roo.get(document.head).select('style').each(function(node) {
13768 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13771 Roo.get(document.head).select('link').each(function(node) {
13772 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13775 } else if (!this.stylesheets.length) {
13777 st = '<style type="text/css">' +
13778 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13781 Roo.each(this.stylesheets, function(s) {
13782 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
13787 st += '<style type="text/css">' +
13788 'IMG { cursor: pointer } ' +
13792 return '<html><head>' + st +
13793 //<style type="text/css">' +
13794 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13796 ' </head><body class="roo-htmleditor-body"></body></html>';
13800 onRender : function(ct, position)
13803 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13804 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13807 this.el.dom.style.border = '0 none';
13808 this.el.dom.setAttribute('tabIndex', -1);
13809 this.el.addClass('x-hidden hide');
13813 if(Roo.isIE){ // fix IE 1px bogus margin
13814 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13818 this.frameId = Roo.id();
13822 var iframe = this.owner.wrap.createChild({
13824 cls: 'form-control', // bootstrap..
13826 name: this.frameId,
13827 frameBorder : 'no',
13828 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
13833 this.iframe = iframe.dom;
13835 this.assignDocWin();
13837 this.doc.designMode = 'on';
13840 this.doc.write(this.getDocMarkup());
13844 var task = { // must defer to wait for browser to be ready
13846 //console.log("run task?" + this.doc.readyState);
13847 this.assignDocWin();
13848 if(this.doc.body || this.doc.readyState == 'complete'){
13850 this.doc.designMode="on";
13854 Roo.TaskMgr.stop(task);
13855 this.initEditor.defer(10, this);
13862 Roo.TaskMgr.start(task);
13869 onResize : function(w, h)
13871 Roo.log('resize: ' +w + ',' + h );
13872 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13876 if(typeof w == 'number'){
13878 this.iframe.style.width = w + 'px';
13880 if(typeof h == 'number'){
13882 this.iframe.style.height = h + 'px';
13884 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13891 * Toggles the editor between standard and source edit mode.
13892 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13894 toggleSourceEdit : function(sourceEditMode){
13896 this.sourceEditMode = sourceEditMode === true;
13898 if(this.sourceEditMode){
13900 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13903 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13904 //this.iframe.className = '';
13907 //this.setSize(this.owner.wrap.getSize());
13908 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13915 * Protected method that will not generally be called directly. If you need/want
13916 * custom HTML cleanup, this is the method you should override.
13917 * @param {String} html The HTML to be cleaned
13918 * return {String} The cleaned HTML
13920 cleanHtml : function(html){
13921 html = String(html);
13922 if(html.length > 5){
13923 if(Roo.isSafari){ // strip safari nonsense
13924 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13927 if(html == ' '){
13934 * HTML Editor -> Textarea
13935 * Protected method that will not generally be called directly. Syncs the contents
13936 * of the editor iframe with the textarea.
13938 syncValue : function(){
13939 if(this.initialized){
13940 var bd = (this.doc.body || this.doc.documentElement);
13941 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13942 var html = bd.innerHTML;
13944 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13945 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13947 html = '<div style="'+m[0]+'">' + html + '</div>';
13950 html = this.cleanHtml(html);
13951 // fix up the special chars.. normaly like back quotes in word...
13952 // however we do not want to do this with chinese..
13953 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13954 var cc = b.charCodeAt();
13956 (cc >= 0x4E00 && cc < 0xA000 ) ||
13957 (cc >= 0x3400 && cc < 0x4E00 ) ||
13958 (cc >= 0xf900 && cc < 0xfb00 )
13964 if(this.owner.fireEvent('beforesync', this, html) !== false){
13965 this.el.dom.value = html;
13966 this.owner.fireEvent('sync', this, html);
13972 * Protected method that will not generally be called directly. Pushes the value of the textarea
13973 * into the iframe editor.
13975 pushValue : function(){
13976 if(this.initialized){
13977 var v = this.el.dom.value.trim();
13979 // if(v.length < 1){
13983 if(this.owner.fireEvent('beforepush', this, v) !== false){
13984 var d = (this.doc.body || this.doc.documentElement);
13986 this.cleanUpPaste();
13987 this.el.dom.value = d.innerHTML;
13988 this.owner.fireEvent('push', this, v);
13994 deferFocus : function(){
13995 this.focus.defer(10, this);
13999 focus : function(){
14000 if(this.win && !this.sourceEditMode){
14007 assignDocWin: function()
14009 var iframe = this.iframe;
14012 this.doc = iframe.contentWindow.document;
14013 this.win = iframe.contentWindow;
14015 if (!Roo.get(this.frameId)) {
14018 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14019 this.win = Roo.get(this.frameId).dom.contentWindow;
14024 initEditor : function(){
14025 //console.log("INIT EDITOR");
14026 this.assignDocWin();
14030 this.doc.designMode="on";
14032 this.doc.write(this.getDocMarkup());
14035 var dbody = (this.doc.body || this.doc.documentElement);
14036 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14037 // this copies styles from the containing element into thsi one..
14038 // not sure why we need all of this..
14039 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14040 ss['background-attachment'] = 'fixed'; // w3c
14041 dbody.bgProperties = 'fixed'; // ie
14042 Roo.DomHelper.applyStyles(dbody, ss);
14043 Roo.EventManager.on(this.doc, {
14044 //'mousedown': this.onEditorEvent,
14045 'mouseup': this.onEditorEvent,
14046 'dblclick': this.onEditorEvent,
14047 'click': this.onEditorEvent,
14048 'keyup': this.onEditorEvent,
14053 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14055 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14056 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14058 this.initialized = true;
14060 this.owner.fireEvent('initialize', this);
14065 onDestroy : function(){
14071 //for (var i =0; i < this.toolbars.length;i++) {
14072 // // fixme - ask toolbars for heights?
14073 // this.toolbars[i].onDestroy();
14076 //this.wrap.dom.innerHTML = '';
14077 //this.wrap.remove();
14082 onFirstFocus : function(){
14084 this.assignDocWin();
14087 this.activated = true;
14090 if(Roo.isGecko){ // prevent silly gecko errors
14092 var s = this.win.getSelection();
14093 if(!s.focusNode || s.focusNode.nodeType != 3){
14094 var r = s.getRangeAt(0);
14095 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14100 this.execCmd('useCSS', true);
14101 this.execCmd('styleWithCSS', false);
14104 this.owner.fireEvent('activate', this);
14108 adjustFont: function(btn){
14109 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14110 //if(Roo.isSafari){ // safari
14113 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14114 if(Roo.isSafari){ // safari
14115 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14116 v = (v < 10) ? 10 : v;
14117 v = (v > 48) ? 48 : v;
14118 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14123 v = Math.max(1, v+adjust);
14125 this.execCmd('FontSize', v );
14128 onEditorEvent : function(e){
14129 this.owner.fireEvent('editorevent', this, e);
14130 // this.updateToolbar();
14131 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14134 insertTag : function(tg)
14136 // could be a bit smarter... -> wrap the current selected tRoo..
14137 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14139 range = this.createRange(this.getSelection());
14140 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14141 wrappingNode.appendChild(range.extractContents());
14142 range.insertNode(wrappingNode);
14149 this.execCmd("formatblock", tg);
14153 insertText : function(txt)
14157 var range = this.createRange();
14158 range.deleteContents();
14159 //alert(Sender.getAttribute('label'));
14161 range.insertNode(this.doc.createTextNode(txt));
14167 * Executes a Midas editor command on the editor document and performs necessary focus and
14168 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14169 * @param {String} cmd The Midas command
14170 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14172 relayCmd : function(cmd, value){
14174 this.execCmd(cmd, value);
14175 this.owner.fireEvent('editorevent', this);
14176 //this.updateToolbar();
14177 this.owner.deferFocus();
14181 * Executes a Midas editor command directly on the editor document.
14182 * For visual commands, you should use {@link #relayCmd} instead.
14183 * <b>This should only be called after the editor is initialized.</b>
14184 * @param {String} cmd The Midas command
14185 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14187 execCmd : function(cmd, value){
14188 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14195 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14197 * @param {String} text | dom node..
14199 insertAtCursor : function(text)
14204 if(!this.activated){
14210 var r = this.doc.selection.createRange();
14221 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14225 // from jquery ui (MIT licenced)
14227 var win = this.win;
14229 if (win.getSelection && win.getSelection().getRangeAt) {
14230 range = win.getSelection().getRangeAt(0);
14231 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14232 range.insertNode(node);
14233 } else if (win.document.selection && win.document.selection.createRange) {
14234 // no firefox support
14235 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14236 win.document.selection.createRange().pasteHTML(txt);
14238 // no firefox support
14239 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14240 this.execCmd('InsertHTML', txt);
14249 mozKeyPress : function(e){
14251 var c = e.getCharCode(), cmd;
14254 c = String.fromCharCode(c).toLowerCase();
14268 this.cleanUpPaste.defer(100, this);
14276 e.preventDefault();
14284 fixKeys : function(){ // load time branching for fastest keydown performance
14286 return function(e){
14287 var k = e.getKey(), r;
14290 r = this.doc.selection.createRange();
14293 r.pasteHTML('    ');
14300 r = this.doc.selection.createRange();
14302 var target = r.parentElement();
14303 if(!target || target.tagName.toLowerCase() != 'li'){
14305 r.pasteHTML('<br />');
14311 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14312 this.cleanUpPaste.defer(100, this);
14318 }else if(Roo.isOpera){
14319 return function(e){
14320 var k = e.getKey();
14324 this.execCmd('InsertHTML','    ');
14327 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14328 this.cleanUpPaste.defer(100, this);
14333 }else if(Roo.isSafari){
14334 return function(e){
14335 var k = e.getKey();
14339 this.execCmd('InsertText','\t');
14343 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14344 this.cleanUpPaste.defer(100, this);
14352 getAllAncestors: function()
14354 var p = this.getSelectedNode();
14357 a.push(p); // push blank onto stack..
14358 p = this.getParentElement();
14362 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14366 a.push(this.doc.body);
14370 lastSelNode : false,
14373 getSelection : function()
14375 this.assignDocWin();
14376 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14379 getSelectedNode: function()
14381 // this may only work on Gecko!!!
14383 // should we cache this!!!!
14388 var range = this.createRange(this.getSelection()).cloneRange();
14391 var parent = range.parentElement();
14393 var testRange = range.duplicate();
14394 testRange.moveToElementText(parent);
14395 if (testRange.inRange(range)) {
14398 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14401 parent = parent.parentElement;
14406 // is ancestor a text element.
14407 var ac = range.commonAncestorContainer;
14408 if (ac.nodeType == 3) {
14409 ac = ac.parentNode;
14412 var ar = ac.childNodes;
14415 var other_nodes = [];
14416 var has_other_nodes = false;
14417 for (var i=0;i<ar.length;i++) {
14418 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14421 // fullly contained node.
14423 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
14428 // probably selected..
14429 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
14430 other_nodes.push(ar[i]);
14434 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
14439 has_other_nodes = true;
14441 if (!nodes.length && other_nodes.length) {
14442 nodes= other_nodes;
14444 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
14450 createRange: function(sel)
14452 // this has strange effects when using with
14453 // top toolbar - not sure if it's a great idea.
14454 //this.editor.contentWindow.focus();
14455 if (typeof sel != "undefined") {
14457 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
14459 return this.doc.createRange();
14462 return this.doc.createRange();
14465 getParentElement: function()
14468 this.assignDocWin();
14469 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
14471 var range = this.createRange(sel);
14474 var p = range.commonAncestorContainer;
14475 while (p.nodeType == 3) { // text node
14486 * Range intersection.. the hard stuff...
14490 * [ -- selected range --- ]
14494 * if end is before start or hits it. fail.
14495 * if start is after end or hits it fail.
14497 * if either hits (but other is outside. - then it's not
14503 // @see http://www.thismuchiknow.co.uk/?p=64.
14504 rangeIntersectsNode : function(range, node)
14506 var nodeRange = node.ownerDocument.createRange();
14508 nodeRange.selectNode(node);
14510 nodeRange.selectNodeContents(node);
14513 var rangeStartRange = range.cloneRange();
14514 rangeStartRange.collapse(true);
14516 var rangeEndRange = range.cloneRange();
14517 rangeEndRange.collapse(false);
14519 var nodeStartRange = nodeRange.cloneRange();
14520 nodeStartRange.collapse(true);
14522 var nodeEndRange = nodeRange.cloneRange();
14523 nodeEndRange.collapse(false);
14525 return rangeStartRange.compareBoundaryPoints(
14526 Range.START_TO_START, nodeEndRange) == -1 &&
14527 rangeEndRange.compareBoundaryPoints(
14528 Range.START_TO_START, nodeStartRange) == 1;
14532 rangeCompareNode : function(range, node)
14534 var nodeRange = node.ownerDocument.createRange();
14536 nodeRange.selectNode(node);
14538 nodeRange.selectNodeContents(node);
14542 range.collapse(true);
14544 nodeRange.collapse(true);
14546 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
14547 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
14549 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
14551 var nodeIsBefore = ss == 1;
14552 var nodeIsAfter = ee == -1;
14554 if (nodeIsBefore && nodeIsAfter)
14556 if (!nodeIsBefore && nodeIsAfter)
14557 return 1; //right trailed.
14559 if (nodeIsBefore && !nodeIsAfter)
14560 return 2; // left trailed.
14565 // private? - in a new class?
14566 cleanUpPaste : function()
14568 // cleans up the whole document..
14569 Roo.log('cleanuppaste');
14571 this.cleanUpChildren(this.doc.body);
14572 var clean = this.cleanWordChars(this.doc.body.innerHTML);
14573 if (clean != this.doc.body.innerHTML) {
14574 this.doc.body.innerHTML = clean;
14579 cleanWordChars : function(input) {// change the chars to hex code
14580 var he = Roo.HtmlEditorCore;
14582 var output = input;
14583 Roo.each(he.swapCodes, function(sw) {
14584 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
14586 output = output.replace(swapper, sw[1]);
14593 cleanUpChildren : function (n)
14595 if (!n.childNodes.length) {
14598 for (var i = n.childNodes.length-1; i > -1 ; i--) {
14599 this.cleanUpChild(n.childNodes[i]);
14606 cleanUpChild : function (node)
14609 //console.log(node);
14610 if (node.nodeName == "#text") {
14611 // clean up silly Windows -- stuff?
14614 if (node.nodeName == "#comment") {
14615 node.parentNode.removeChild(node);
14616 // clean up silly Windows -- stuff?
14620 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
14622 node.parentNode.removeChild(node);
14627 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
14629 // remove <a name=....> as rendering on yahoo mailer is borked with this.
14630 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14632 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14633 // remove_keep_children = true;
14636 if (remove_keep_children) {
14637 this.cleanUpChildren(node);
14638 // inserts everything just before this node...
14639 while (node.childNodes.length) {
14640 var cn = node.childNodes[0];
14641 node.removeChild(cn);
14642 node.parentNode.insertBefore(cn, node);
14644 node.parentNode.removeChild(node);
14648 if (!node.attributes || !node.attributes.length) {
14649 this.cleanUpChildren(node);
14653 function cleanAttr(n,v)
14656 if (v.match(/^\./) || v.match(/^\//)) {
14659 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14662 if (v.match(/^#/)) {
14665 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14666 node.removeAttribute(n);
14670 function cleanStyle(n,v)
14672 if (v.match(/expression/)) { //XSS?? should we even bother..
14673 node.removeAttribute(n);
14676 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14677 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14680 var parts = v.split(/;/);
14683 Roo.each(parts, function(p) {
14684 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14688 var l = p.split(':').shift().replace(/\s+/g,'');
14689 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14691 if ( cblack.indexOf(l) > -1) {
14692 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14693 //node.removeAttribute(n);
14697 // only allow 'c whitelisted system attributes'
14698 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14699 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14700 //node.removeAttribute(n);
14710 if (clean.length) {
14711 node.setAttribute(n, clean.join(';'));
14713 node.removeAttribute(n);
14719 for (var i = node.attributes.length-1; i > -1 ; i--) {
14720 var a = node.attributes[i];
14723 if (a.name.toLowerCase().substr(0,2)=='on') {
14724 node.removeAttribute(a.name);
14727 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14728 node.removeAttribute(a.name);
14731 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14732 cleanAttr(a.name,a.value); // fixme..
14735 if (a.name == 'style') {
14736 cleanStyle(a.name,a.value);
14739 /// clean up MS crap..
14740 // tecnically this should be a list of valid class'es..
14743 if (a.name == 'class') {
14744 if (a.value.match(/^Mso/)) {
14745 node.className = '';
14748 if (a.value.match(/body/)) {
14749 node.className = '';
14760 this.cleanUpChildren(node);
14766 // hide stuff that is not compatible
14780 * @event specialkey
14784 * @cfg {String} fieldClass @hide
14787 * @cfg {String} focusClass @hide
14790 * @cfg {String} autoCreate @hide
14793 * @cfg {String} inputType @hide
14796 * @cfg {String} invalidClass @hide
14799 * @cfg {String} invalidText @hide
14802 * @cfg {String} msgFx @hide
14805 * @cfg {String} validateOnBlur @hide
14809 Roo.HtmlEditorCore.white = [
14810 'area', 'br', 'img', 'input', 'hr', 'wbr',
14812 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14813 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14814 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14815 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14816 'table', 'ul', 'xmp',
14818 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14821 'dir', 'menu', 'ol', 'ul', 'dl',
14827 Roo.HtmlEditorCore.black = [
14828 // 'embed', 'object', // enable - backend responsiblity to clean thiese
14830 'base', 'basefont', 'bgsound', 'blink', 'body',
14831 'frame', 'frameset', 'head', 'html', 'ilayer',
14832 'iframe', 'layer', 'link', 'meta', 'object',
14833 'script', 'style' ,'title', 'xml' // clean later..
14835 Roo.HtmlEditorCore.clean = [
14836 'script', 'style', 'title', 'xml'
14838 Roo.HtmlEditorCore.remove = [
14843 Roo.HtmlEditorCore.ablack = [
14847 Roo.HtmlEditorCore.aclean = [
14848 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14852 Roo.HtmlEditorCore.pwhite= [
14853 'http', 'https', 'mailto'
14856 // white listed style attributes.
14857 Roo.HtmlEditorCore.cwhite= [
14858 // 'text-align', /// default is to allow most things..
14864 // black listed style attributes.
14865 Roo.HtmlEditorCore.cblack= [
14866 // 'font-size' -- this can be set by the project
14870 Roo.HtmlEditorCore.swapCodes =[
14889 * @class Roo.bootstrap.HtmlEditor
14890 * @extends Roo.bootstrap.TextArea
14891 * Bootstrap HtmlEditor class
14894 * Create a new HtmlEditor
14895 * @param {Object} config The config object
14898 Roo.bootstrap.HtmlEditor = function(config){
14899 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14900 if (!this.toolbars) {
14901 this.toolbars = [];
14903 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14906 * @event initialize
14907 * Fires when the editor is fully initialized (including the iframe)
14908 * @param {HtmlEditor} this
14913 * Fires when the editor is first receives the focus. Any insertion must wait
14914 * until after this event.
14915 * @param {HtmlEditor} this
14919 * @event beforesync
14920 * Fires before the textarea is updated with content from the editor iframe. Return false
14921 * to cancel the sync.
14922 * @param {HtmlEditor} this
14923 * @param {String} html
14927 * @event beforepush
14928 * Fires before the iframe editor is updated with content from the textarea. Return false
14929 * to cancel the push.
14930 * @param {HtmlEditor} this
14931 * @param {String} html
14936 * Fires when the textarea is updated with content from the editor iframe.
14937 * @param {HtmlEditor} this
14938 * @param {String} html
14943 * Fires when the iframe editor is updated with content from the textarea.
14944 * @param {HtmlEditor} this
14945 * @param {String} html
14949 * @event editmodechange
14950 * Fires when the editor switches edit modes
14951 * @param {HtmlEditor} this
14952 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14954 editmodechange: true,
14956 * @event editorevent
14957 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14958 * @param {HtmlEditor} this
14962 * @event firstfocus
14963 * Fires when on first focus - needed by toolbars..
14964 * @param {HtmlEditor} this
14969 * Auto save the htmlEditor value as a file into Events
14970 * @param {HtmlEditor} this
14974 * @event savedpreview
14975 * preview the saved version of htmlEditor
14976 * @param {HtmlEditor} this
14983 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14987 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14992 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14997 * @cfg {Number} height (in pixels)
15001 * @cfg {Number} width (in pixels)
15006 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15009 stylesheets: false,
15014 // private properties
15015 validationEvent : false,
15017 initialized : false,
15020 onFocus : Roo.emptyFn,
15022 hideMode:'offsets',
15025 tbContainer : false,
15027 toolbarContainer :function() {
15028 return this.wrap.select('.x-html-editor-tb',true).first();
15032 * Protected method that will not generally be called directly. It
15033 * is called when the editor creates its toolbar. Override this method if you need to
15034 * add custom toolbar buttons.
15035 * @param {HtmlEditor} editor
15037 createToolbar : function(){
15039 Roo.log("create toolbars");
15041 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15042 this.toolbars[0].render(this.toolbarContainer());
15046 // if (!editor.toolbars || !editor.toolbars.length) {
15047 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15050 // for (var i =0 ; i < editor.toolbars.length;i++) {
15051 // editor.toolbars[i] = Roo.factory(
15052 // typeof(editor.toolbars[i]) == 'string' ?
15053 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15054 // Roo.bootstrap.HtmlEditor);
15055 // editor.toolbars[i].init(editor);
15061 onRender : function(ct, position)
15063 // Roo.log("Call onRender: " + this.xtype);
15065 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15067 this.wrap = this.inputEl().wrap({
15068 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15071 this.editorcore.onRender(ct, position);
15073 if (this.resizable) {
15074 this.resizeEl = new Roo.Resizable(this.wrap, {
15078 minHeight : this.height,
15079 height: this.height,
15080 handles : this.resizable,
15083 resize : function(r, w, h) {
15084 _t.onResize(w,h); // -something
15090 this.createToolbar(this);
15093 if(!this.width && this.resizable){
15094 this.setSize(this.wrap.getSize());
15096 if (this.resizeEl) {
15097 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15098 // should trigger onReize..
15104 onResize : function(w, h)
15106 Roo.log('resize: ' +w + ',' + h );
15107 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15111 if(this.inputEl() ){
15112 if(typeof w == 'number'){
15113 var aw = w - this.wrap.getFrameWidth('lr');
15114 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15117 if(typeof h == 'number'){
15118 var tbh = -11; // fixme it needs to tool bar size!
15119 for (var i =0; i < this.toolbars.length;i++) {
15120 // fixme - ask toolbars for heights?
15121 tbh += this.toolbars[i].el.getHeight();
15122 //if (this.toolbars[i].footer) {
15123 // tbh += this.toolbars[i].footer.el.getHeight();
15131 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15132 ah -= 5; // knock a few pixes off for look..
15133 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15137 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15138 this.editorcore.onResize(ew,eh);
15143 * Toggles the editor between standard and source edit mode.
15144 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15146 toggleSourceEdit : function(sourceEditMode)
15148 this.editorcore.toggleSourceEdit(sourceEditMode);
15150 if(this.editorcore.sourceEditMode){
15151 Roo.log('editor - showing textarea');
15154 // Roo.log(this.syncValue());
15156 this.inputEl().removeClass('hide');
15157 this.inputEl().dom.removeAttribute('tabIndex');
15158 this.inputEl().focus();
15160 Roo.log('editor - hiding textarea');
15162 // Roo.log(this.pushValue());
15165 this.inputEl().addClass('hide');
15166 this.inputEl().dom.setAttribute('tabIndex', -1);
15167 //this.deferFocus();
15170 if(this.resizable){
15171 this.setSize(this.wrap.getSize());
15174 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15177 // private (for BoxComponent)
15178 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15180 // private (for BoxComponent)
15181 getResizeEl : function(){
15185 // private (for BoxComponent)
15186 getPositionEl : function(){
15191 initEvents : function(){
15192 this.originalValue = this.getValue();
15196 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15199 // markInvalid : Roo.emptyFn,
15201 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15204 // clearInvalid : Roo.emptyFn,
15206 setValue : function(v){
15207 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15208 this.editorcore.pushValue();
15213 deferFocus : function(){
15214 this.focus.defer(10, this);
15218 focus : function(){
15219 this.editorcore.focus();
15225 onDestroy : function(){
15231 for (var i =0; i < this.toolbars.length;i++) {
15232 // fixme - ask toolbars for heights?
15233 this.toolbars[i].onDestroy();
15236 this.wrap.dom.innerHTML = '';
15237 this.wrap.remove();
15242 onFirstFocus : function(){
15243 //Roo.log("onFirstFocus");
15244 this.editorcore.onFirstFocus();
15245 for (var i =0; i < this.toolbars.length;i++) {
15246 this.toolbars[i].onFirstFocus();
15252 syncValue : function()
15254 this.editorcore.syncValue();
15257 pushValue : function()
15259 this.editorcore.pushValue();
15263 // hide stuff that is not compatible
15277 * @event specialkey
15281 * @cfg {String} fieldClass @hide
15284 * @cfg {String} focusClass @hide
15287 * @cfg {String} autoCreate @hide
15290 * @cfg {String} inputType @hide
15293 * @cfg {String} invalidClass @hide
15296 * @cfg {String} invalidText @hide
15299 * @cfg {String} msgFx @hide
15302 * @cfg {String} validateOnBlur @hide
15313 * @class Roo.bootstrap.HtmlEditorToolbar1
15318 new Roo.bootstrap.HtmlEditor({
15321 new Roo.bootstrap.HtmlEditorToolbar1({
15322 disable : { fonts: 1 , format: 1, ..., ... , ...],
15328 * @cfg {Object} disable List of elements to disable..
15329 * @cfg {Array} btns List of additional buttons.
15333 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
15336 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
15339 Roo.apply(this, config);
15341 // default disabled, based on 'good practice'..
15342 this.disable = this.disable || {};
15343 Roo.applyIf(this.disable, {
15346 specialElements : true
15348 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
15350 this.editor = config.editor;
15351 this.editorcore = config.editor.editorcore;
15353 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
15355 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
15356 // dont call parent... till later.
15358 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
15364 editorcore : false,
15369 "h1","h2","h3","h4","h5","h6",
15371 "abbr", "acronym", "address", "cite", "samp", "var",
15375 onRender : function(ct, position)
15377 // Roo.log("Call onRender: " + this.xtype);
15379 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
15381 this.el.dom.style.marginBottom = '0';
15383 var editorcore = this.editorcore;
15384 var editor= this.editor;
15387 var btn = function(id,cmd , toggle, handler){
15389 var event = toggle ? 'toggle' : 'click';
15394 xns: Roo.bootstrap,
15397 enableToggle:toggle !== false,
15399 pressed : toggle ? false : null,
15402 a.listeners[toggle ? 'toggle' : 'click'] = function() {
15403 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
15412 xns: Roo.bootstrap,
15413 glyphicon : 'font',
15417 xns: Roo.bootstrap,
15421 Roo.each(this.formats, function(f) {
15422 style.menu.items.push({
15424 xns: Roo.bootstrap,
15425 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
15430 editorcore.insertTag(this.tagname);
15437 children.push(style);
15440 btn('bold',false,true);
15441 btn('italic',false,true);
15442 btn('align-left', 'justifyleft',true);
15443 btn('align-center', 'justifycenter',true);
15444 btn('align-right' , 'justifyright',true);
15445 btn('link', false, false, function(btn) {
15446 //Roo.log("create link?");
15447 var url = prompt(this.createLinkText, this.defaultLinkValue);
15448 if(url && url != 'http:/'+'/'){
15449 this.editorcore.relayCmd('createlink', url);
15452 btn('list','insertunorderedlist',true);
15453 btn('pencil', false,true, function(btn){
15456 this.toggleSourceEdit(btn.pressed);
15462 xns: Roo.bootstrap,
15467 xns: Roo.bootstrap,
15472 cog.menu.items.push({
15474 xns: Roo.bootstrap,
15475 html : Clean styles,
15480 editorcore.insertTag(this.tagname);
15489 this.xtype = 'Navbar';
15491 for(var i=0;i< children.length;i++) {
15493 this.buttons.add(this.addxtypeChild(children[i]));
15497 editor.on('editorevent', this.updateToolbar, this);
15499 onBtnClick : function(id)
15501 this.editorcore.relayCmd(id);
15502 this.editorcore.focus();
15506 * Protected method that will not generally be called directly. It triggers
15507 * a toolbar update by reading the markup state of the current selection in the editor.
15509 updateToolbar: function(){
15511 if(!this.editorcore.activated){
15512 this.editor.onFirstFocus(); // is this neeed?
15516 var btns = this.buttons;
15517 var doc = this.editorcore.doc;
15518 btns.get('bold').setActive(doc.queryCommandState('bold'));
15519 btns.get('italic').setActive(doc.queryCommandState('italic'));
15520 //btns.get('underline').setActive(doc.queryCommandState('underline'));
15522 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
15523 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
15524 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
15526 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
15527 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
15530 var ans = this.editorcore.getAllAncestors();
15531 if (this.formatCombo) {
15534 var store = this.formatCombo.store;
15535 this.formatCombo.setValue("");
15536 for (var i =0; i < ans.length;i++) {
15537 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
15539 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
15547 // hides menus... - so this cant be on a menu...
15548 Roo.bootstrap.MenuMgr.hideAll();
15550 Roo.bootstrap.MenuMgr.hideAll();
15551 //this.editorsyncValue();
15553 onFirstFocus: function() {
15554 this.buttons.each(function(item){
15558 toggleSourceEdit : function(sourceEditMode){
15561 if(sourceEditMode){
15562 Roo.log("disabling buttons");
15563 this.buttons.each( function(item){
15564 if(item.cmd != 'pencil'){
15570 Roo.log("enabling buttons");
15571 if(this.editorcore.initialized){
15572 this.buttons.each( function(item){
15578 Roo.log("calling toggole on editor");
15579 // tell the editor that it's been pressed..
15580 this.editor.toggleSourceEdit(sourceEditMode);
15590 * @class Roo.bootstrap.Table.AbstractSelectionModel
15591 * @extends Roo.util.Observable
15592 * Abstract base class for grid SelectionModels. It provides the interface that should be
15593 * implemented by descendant classes. This class should not be directly instantiated.
15596 Roo.bootstrap.Table.AbstractSelectionModel = function(){
15597 this.locked = false;
15598 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
15602 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
15603 /** @ignore Called by the grid automatically. Do not call directly. */
15604 init : function(grid){
15610 * Locks the selections.
15613 this.locked = true;
15617 * Unlocks the selections.
15619 unlock : function(){
15620 this.locked = false;
15624 * Returns true if the selections are locked.
15625 * @return {Boolean}
15627 isLocked : function(){
15628 return this.locked;
15632 * @class Roo.bootstrap.Table.ColumnModel
15633 * @extends Roo.util.Observable
15634 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15635 * the columns in the table.
15638 * @param {Object} config An Array of column config objects. See this class's
15639 * config objects for details.
15641 Roo.bootstrap.Table.ColumnModel = function(config){
15643 * The config passed into the constructor
15645 this.config = config;
15648 // if no id, create one
15649 // if the column does not have a dataIndex mapping,
15650 // map it to the order it is in the config
15651 for(var i = 0, len = config.length; i < len; i++){
15653 if(typeof c.dataIndex == "undefined"){
15656 if(typeof c.renderer == "string"){
15657 c.renderer = Roo.util.Format[c.renderer];
15659 if(typeof c.id == "undefined"){
15662 // if(c.editor && c.editor.xtype){
15663 // c.editor = Roo.factory(c.editor, Roo.grid);
15665 // if(c.editor && c.editor.isFormField){
15666 // c.editor = new Roo.grid.GridEditor(c.editor);
15669 this.lookup[c.id] = c;
15673 * The width of columns which have no width specified (defaults to 100)
15676 this.defaultWidth = 100;
15679 * Default sortable of columns which have no sortable specified (defaults to false)
15682 this.defaultSortable = false;
15686 * @event widthchange
15687 * Fires when the width of a column changes.
15688 * @param {ColumnModel} this
15689 * @param {Number} columnIndex The column index
15690 * @param {Number} newWidth The new width
15692 "widthchange": true,
15694 * @event headerchange
15695 * Fires when the text of a header changes.
15696 * @param {ColumnModel} this
15697 * @param {Number} columnIndex The column index
15698 * @param {Number} newText The new header text
15700 "headerchange": true,
15702 * @event hiddenchange
15703 * Fires when a column is hidden or "unhidden".
15704 * @param {ColumnModel} this
15705 * @param {Number} columnIndex The column index
15706 * @param {Boolean} hidden true if hidden, false otherwise
15708 "hiddenchange": true,
15710 * @event columnmoved
15711 * Fires when a column is moved.
15712 * @param {ColumnModel} this
15713 * @param {Number} oldIndex
15714 * @param {Number} newIndex
15716 "columnmoved" : true,
15718 * @event columlockchange
15719 * Fires when a column's locked state is changed
15720 * @param {ColumnModel} this
15721 * @param {Number} colIndex
15722 * @param {Boolean} locked true if locked
15724 "columnlockchange" : true
15726 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15728 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15730 * @cfg {String} header The header text to display in the Grid view.
15733 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15734 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15735 * specified, the column's index is used as an index into the Record's data Array.
15738 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15739 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15742 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15743 * Defaults to the value of the {@link #defaultSortable} property.
15744 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
15747 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
15750 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
15753 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
15756 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
15759 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
15760 * given the cell's data value. See {@link #setRenderer}. If not specified, the
15761 * default renderer uses the raw data value.
15764 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
15768 * Returns the id of the column at the specified index.
15769 * @param {Number} index The column index
15770 * @return {String} the id
15772 getColumnId : function(index){
15773 return this.config[index].id;
15777 * Returns the column for a specified id.
15778 * @param {String} id The column id
15779 * @return {Object} the column
15781 getColumnById : function(id){
15782 return this.lookup[id];
15787 * Returns the column for a specified dataIndex.
15788 * @param {String} dataIndex The column dataIndex
15789 * @return {Object|Boolean} the column or false if not found
15791 getColumnByDataIndex: function(dataIndex){
15792 var index = this.findColumnIndex(dataIndex);
15793 return index > -1 ? this.config[index] : false;
15797 * Returns the index for a specified column id.
15798 * @param {String} id The column id
15799 * @return {Number} the index, or -1 if not found
15801 getIndexById : function(id){
15802 for(var i = 0, len = this.config.length; i < len; i++){
15803 if(this.config[i].id == id){
15811 * Returns the index for a specified column dataIndex.
15812 * @param {String} dataIndex The column dataIndex
15813 * @return {Number} the index, or -1 if not found
15816 findColumnIndex : function(dataIndex){
15817 for(var i = 0, len = this.config.length; i < len; i++){
15818 if(this.config[i].dataIndex == dataIndex){
15826 moveColumn : function(oldIndex, newIndex){
15827 var c = this.config[oldIndex];
15828 this.config.splice(oldIndex, 1);
15829 this.config.splice(newIndex, 0, c);
15830 this.dataMap = null;
15831 this.fireEvent("columnmoved", this, oldIndex, newIndex);
15834 isLocked : function(colIndex){
15835 return this.config[colIndex].locked === true;
15838 setLocked : function(colIndex, value, suppressEvent){
15839 if(this.isLocked(colIndex) == value){
15842 this.config[colIndex].locked = value;
15843 if(!suppressEvent){
15844 this.fireEvent("columnlockchange", this, colIndex, value);
15848 getTotalLockedWidth : function(){
15849 var totalWidth = 0;
15850 for(var i = 0; i < this.config.length; i++){
15851 if(this.isLocked(i) && !this.isHidden(i)){
15852 this.totalWidth += this.getColumnWidth(i);
15858 getLockedCount : function(){
15859 for(var i = 0, len = this.config.length; i < len; i++){
15860 if(!this.isLocked(i)){
15867 * Returns the number of columns.
15870 getColumnCount : function(visibleOnly){
15871 if(visibleOnly === true){
15873 for(var i = 0, len = this.config.length; i < len; i++){
15874 if(!this.isHidden(i)){
15880 return this.config.length;
15884 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15885 * @param {Function} fn
15886 * @param {Object} scope (optional)
15887 * @return {Array} result
15889 getColumnsBy : function(fn, scope){
15891 for(var i = 0, len = this.config.length; i < len; i++){
15892 var c = this.config[i];
15893 if(fn.call(scope||this, c, i) === true){
15901 * Returns true if the specified column is sortable.
15902 * @param {Number} col The column index
15903 * @return {Boolean}
15905 isSortable : function(col){
15906 if(typeof this.config[col].sortable == "undefined"){
15907 return this.defaultSortable;
15909 return this.config[col].sortable;
15913 * Returns the rendering (formatting) function defined for the column.
15914 * @param {Number} col The column index.
15915 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15917 getRenderer : function(col){
15918 if(!this.config[col].renderer){
15919 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15921 return this.config[col].renderer;
15925 * Sets the rendering (formatting) function for a column.
15926 * @param {Number} col The column index
15927 * @param {Function} fn The function to use to process the cell's raw data
15928 * to return HTML markup for the grid view. The render function is called with
15929 * the following parameters:<ul>
15930 * <li>Data value.</li>
15931 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15932 * <li>css A CSS style string to apply to the table cell.</li>
15933 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15934 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15935 * <li>Row index</li>
15936 * <li>Column index</li>
15937 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15939 setRenderer : function(col, fn){
15940 this.config[col].renderer = fn;
15944 * Returns the width for the specified column.
15945 * @param {Number} col The column index
15948 getColumnWidth : function(col){
15949 return this.config[col].width * 1 || this.defaultWidth;
15953 * Sets the width for a column.
15954 * @param {Number} col The column index
15955 * @param {Number} width The new width
15957 setColumnWidth : function(col, width, suppressEvent){
15958 this.config[col].width = width;
15959 this.totalWidth = null;
15960 if(!suppressEvent){
15961 this.fireEvent("widthchange", this, col, width);
15966 * Returns the total width of all columns.
15967 * @param {Boolean} includeHidden True to include hidden column widths
15970 getTotalWidth : function(includeHidden){
15971 if(!this.totalWidth){
15972 this.totalWidth = 0;
15973 for(var i = 0, len = this.config.length; i < len; i++){
15974 if(includeHidden || !this.isHidden(i)){
15975 this.totalWidth += this.getColumnWidth(i);
15979 return this.totalWidth;
15983 * Returns the header for the specified column.
15984 * @param {Number} col The column index
15987 getColumnHeader : function(col){
15988 return this.config[col].header;
15992 * Sets the header for a column.
15993 * @param {Number} col The column index
15994 * @param {String} header The new header
15996 setColumnHeader : function(col, header){
15997 this.config[col].header = header;
15998 this.fireEvent("headerchange", this, col, header);
16002 * Returns the tooltip for the specified column.
16003 * @param {Number} col The column index
16006 getColumnTooltip : function(col){
16007 return this.config[col].tooltip;
16010 * Sets the tooltip for a column.
16011 * @param {Number} col The column index
16012 * @param {String} tooltip The new tooltip
16014 setColumnTooltip : function(col, tooltip){
16015 this.config[col].tooltip = tooltip;
16019 * Returns the dataIndex for the specified column.
16020 * @param {Number} col The column index
16023 getDataIndex : function(col){
16024 return this.config[col].dataIndex;
16028 * Sets the dataIndex for a column.
16029 * @param {Number} col The column index
16030 * @param {Number} dataIndex The new dataIndex
16032 setDataIndex : function(col, dataIndex){
16033 this.config[col].dataIndex = dataIndex;
16039 * Returns true if the cell is editable.
16040 * @param {Number} colIndex The column index
16041 * @param {Number} rowIndex The row index
16042 * @return {Boolean}
16044 isCellEditable : function(colIndex, rowIndex){
16045 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16049 * Returns the editor defined for the cell/column.
16050 * return false or null to disable editing.
16051 * @param {Number} colIndex The column index
16052 * @param {Number} rowIndex The row index
16055 getCellEditor : function(colIndex, rowIndex){
16056 return this.config[colIndex].editor;
16060 * Sets if a column is editable.
16061 * @param {Number} col The column index
16062 * @param {Boolean} editable True if the column is editable
16064 setEditable : function(col, editable){
16065 this.config[col].editable = editable;
16070 * Returns true if the column is hidden.
16071 * @param {Number} colIndex The column index
16072 * @return {Boolean}
16074 isHidden : function(colIndex){
16075 return this.config[colIndex].hidden;
16080 * Returns true if the column width cannot be changed
16082 isFixed : function(colIndex){
16083 return this.config[colIndex].fixed;
16087 * Returns true if the column can be resized
16088 * @return {Boolean}
16090 isResizable : function(colIndex){
16091 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16094 * Sets if a column is hidden.
16095 * @param {Number} colIndex The column index
16096 * @param {Boolean} hidden True if the column is hidden
16098 setHidden : function(colIndex, hidden){
16099 this.config[colIndex].hidden = hidden;
16100 this.totalWidth = null;
16101 this.fireEvent("hiddenchange", this, colIndex, hidden);
16105 * Sets the editor for a column.
16106 * @param {Number} col The column index
16107 * @param {Object} editor The editor object
16109 setEditor : function(col, editor){
16110 this.config[col].editor = editor;
16114 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16115 if(typeof value == "string" && value.length < 1){
16121 // Alias for backwards compatibility
16122 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16125 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16126 * @class Roo.bootstrap.Table.RowSelectionModel
16127 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16128 * It supports multiple selections and keyboard selection/navigation.
16130 * @param {Object} config
16133 Roo.bootstrap.Table.RowSelectionModel = function(config){
16134 Roo.apply(this, config);
16135 this.selections = new Roo.util.MixedCollection(false, function(o){
16140 this.lastActive = false;
16144 * @event selectionchange
16145 * Fires when the selection changes
16146 * @param {SelectionModel} this
16148 "selectionchange" : true,
16150 * @event afterselectionchange
16151 * Fires after the selection changes (eg. by key press or clicking)
16152 * @param {SelectionModel} this
16154 "afterselectionchange" : true,
16156 * @event beforerowselect
16157 * Fires when a row is selected being selected, return false to cancel.
16158 * @param {SelectionModel} this
16159 * @param {Number} rowIndex The selected index
16160 * @param {Boolean} keepExisting False if other selections will be cleared
16162 "beforerowselect" : true,
16165 * Fires when a row is selected.
16166 * @param {SelectionModel} this
16167 * @param {Number} rowIndex The selected index
16168 * @param {Roo.data.Record} r The record
16170 "rowselect" : true,
16172 * @event rowdeselect
16173 * Fires when a row is deselected.
16174 * @param {SelectionModel} this
16175 * @param {Number} rowIndex The selected index
16177 "rowdeselect" : true
16179 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16180 this.locked = false;
16183 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16185 * @cfg {Boolean} singleSelect
16186 * True to allow selection of only one row at a time (defaults to false)
16188 singleSelect : false,
16191 initEvents : function(){
16193 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16194 this.grid.on("mousedown", this.handleMouseDown, this);
16195 }else{ // allow click to work like normal
16196 this.grid.on("rowclick", this.handleDragableRowClick, this);
16199 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16200 "up" : function(e){
16202 this.selectPrevious(e.shiftKey);
16203 }else if(this.last !== false && this.lastActive !== false){
16204 var last = this.last;
16205 this.selectRange(this.last, this.lastActive-1);
16206 this.grid.getView().focusRow(this.lastActive);
16207 if(last !== false){
16211 this.selectFirstRow();
16213 this.fireEvent("afterselectionchange", this);
16215 "down" : function(e){
16217 this.selectNext(e.shiftKey);
16218 }else if(this.last !== false && this.lastActive !== false){
16219 var last = this.last;
16220 this.selectRange(this.last, this.lastActive+1);
16221 this.grid.getView().focusRow(this.lastActive);
16222 if(last !== false){
16226 this.selectFirstRow();
16228 this.fireEvent("afterselectionchange", this);
16233 var view = this.grid.view;
16234 view.on("refresh", this.onRefresh, this);
16235 view.on("rowupdated", this.onRowUpdated, this);
16236 view.on("rowremoved", this.onRemove, this);
16240 onRefresh : function(){
16241 var ds = this.grid.dataSource, i, v = this.grid.view;
16242 var s = this.selections;
16243 s.each(function(r){
16244 if((i = ds.indexOfId(r.id)) != -1){
16253 onRemove : function(v, index, r){
16254 this.selections.remove(r);
16258 onRowUpdated : function(v, index, r){
16259 if(this.isSelected(r)){
16260 v.onRowSelect(index);
16266 * @param {Array} records The records to select
16267 * @param {Boolean} keepExisting (optional) True to keep existing selections
16269 selectRecords : function(records, keepExisting){
16271 this.clearSelections();
16273 var ds = this.grid.dataSource;
16274 for(var i = 0, len = records.length; i < len; i++){
16275 this.selectRow(ds.indexOf(records[i]), true);
16280 * Gets the number of selected rows.
16283 getCount : function(){
16284 return this.selections.length;
16288 * Selects the first row in the grid.
16290 selectFirstRow : function(){
16295 * Select the last row.
16296 * @param {Boolean} keepExisting (optional) True to keep existing selections
16298 selectLastRow : function(keepExisting){
16299 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
16303 * Selects the row immediately following the last selected row.
16304 * @param {Boolean} keepExisting (optional) True to keep existing selections
16306 selectNext : function(keepExisting){
16307 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
16308 this.selectRow(this.last+1, keepExisting);
16309 this.grid.getView().focusRow(this.last);
16314 * Selects the row that precedes the last selected row.
16315 * @param {Boolean} keepExisting (optional) True to keep existing selections
16317 selectPrevious : function(keepExisting){
16319 this.selectRow(this.last-1, keepExisting);
16320 this.grid.getView().focusRow(this.last);
16325 * Returns the selected records
16326 * @return {Array} Array of selected records
16328 getSelections : function(){
16329 return [].concat(this.selections.items);
16333 * Returns the first selected record.
16336 getSelected : function(){
16337 return this.selections.itemAt(0);
16342 * Clears all selections.
16344 clearSelections : function(fast){
16345 if(this.locked) return;
16347 var ds = this.grid.dataSource;
16348 var s = this.selections;
16349 s.each(function(r){
16350 this.deselectRow(ds.indexOfId(r.id));
16354 this.selections.clear();
16361 * Selects all rows.
16363 selectAll : function(){
16364 if(this.locked) return;
16365 this.selections.clear();
16366 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
16367 this.selectRow(i, true);
16372 * Returns True if there is a selection.
16373 * @return {Boolean}
16375 hasSelection : function(){
16376 return this.selections.length > 0;
16380 * Returns True if the specified row is selected.
16381 * @param {Number/Record} record The record or index of the record to check
16382 * @return {Boolean}
16384 isSelected : function(index){
16385 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
16386 return (r && this.selections.key(r.id) ? true : false);
16390 * Returns True if the specified record id is selected.
16391 * @param {String} id The id of record to check
16392 * @return {Boolean}
16394 isIdSelected : function(id){
16395 return (this.selections.key(id) ? true : false);
16399 handleMouseDown : function(e, t){
16400 var view = this.grid.getView(), rowIndex;
16401 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
16404 if(e.shiftKey && this.last !== false){
16405 var last = this.last;
16406 this.selectRange(last, rowIndex, e.ctrlKey);
16407 this.last = last; // reset the last
16408 view.focusRow(rowIndex);
16410 var isSelected = this.isSelected(rowIndex);
16411 if(e.button !== 0 && isSelected){
16412 view.focusRow(rowIndex);
16413 }else if(e.ctrlKey && isSelected){
16414 this.deselectRow(rowIndex);
16415 }else if(!isSelected){
16416 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
16417 view.focusRow(rowIndex);
16420 this.fireEvent("afterselectionchange", this);
16423 handleDragableRowClick : function(grid, rowIndex, e)
16425 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
16426 this.selectRow(rowIndex, false);
16427 grid.view.focusRow(rowIndex);
16428 this.fireEvent("afterselectionchange", this);
16433 * Selects multiple rows.
16434 * @param {Array} rows Array of the indexes of the row to select
16435 * @param {Boolean} keepExisting (optional) True to keep existing selections
16437 selectRows : function(rows, keepExisting){
16439 this.clearSelections();
16441 for(var i = 0, len = rows.length; i < len; i++){
16442 this.selectRow(rows[i], true);
16447 * Selects a range of rows. All rows in between startRow and endRow are also selected.
16448 * @param {Number} startRow The index of the first row in the range
16449 * @param {Number} endRow The index of the last row in the range
16450 * @param {Boolean} keepExisting (optional) True to retain existing selections
16452 selectRange : function(startRow, endRow, keepExisting){
16453 if(this.locked) return;
16455 this.clearSelections();
16457 if(startRow <= endRow){
16458 for(var i = startRow; i <= endRow; i++){
16459 this.selectRow(i, true);
16462 for(var i = startRow; i >= endRow; i--){
16463 this.selectRow(i, true);
16469 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
16470 * @param {Number} startRow The index of the first row in the range
16471 * @param {Number} endRow The index of the last row in the range
16473 deselectRange : function(startRow, endRow, preventViewNotify){
16474 if(this.locked) return;
16475 for(var i = startRow; i <= endRow; i++){
16476 this.deselectRow(i, preventViewNotify);
16482 * @param {Number} row The index of the row to select
16483 * @param {Boolean} keepExisting (optional) True to keep existing selections
16485 selectRow : function(index, keepExisting, preventViewNotify){
16486 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
16487 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
16488 if(!keepExisting || this.singleSelect){
16489 this.clearSelections();
16491 var r = this.grid.dataSource.getAt(index);
16492 this.selections.add(r);
16493 this.last = this.lastActive = index;
16494 if(!preventViewNotify){
16495 this.grid.getView().onRowSelect(index);
16497 this.fireEvent("rowselect", this, index, r);
16498 this.fireEvent("selectionchange", this);
16504 * @param {Number} row The index of the row to deselect
16506 deselectRow : function(index, preventViewNotify){
16507 if(this.locked) return;
16508 if(this.last == index){
16511 if(this.lastActive == index){
16512 this.lastActive = false;
16514 var r = this.grid.dataSource.getAt(index);
16515 this.selections.remove(r);
16516 if(!preventViewNotify){
16517 this.grid.getView().onRowDeselect(index);
16519 this.fireEvent("rowdeselect", this, index);
16520 this.fireEvent("selectionchange", this);
16524 restoreLast : function(){
16526 this.last = this._last;
16531 acceptsNav : function(row, col, cm){
16532 return !cm.isHidden(col) && cm.isCellEditable(col, row);
16536 onEditorKey : function(field, e){
16537 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
16542 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
16544 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
16546 }else if(k == e.ENTER && !e.ctrlKey){
16550 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
16552 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
16554 }else if(k == e.ESC){
16558 g.startEditing(newCell[0], newCell[1]);
16569 * @class Roo.bootstrap.MessageBar
16570 * @extends Roo.bootstrap.Component
16571 * Bootstrap MessageBar class
16572 * @cfg {String} html contents of the MessageBar
16573 * @cfg {String} weight (info | success | warning | danger) default info
16574 * @cfg {String} beforeClass insert the bar before the given class
16575 * @cfg {Boolean} closable (true | false) default false
16576 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
16579 * Create a new Element
16580 * @param {Object} config The config object
16583 Roo.bootstrap.MessageBar = function(config){
16584 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
16587 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
16593 beforeClass: 'bootstrap-sticky-wrap',
16595 getAutoCreate : function(){
16599 cls: 'alert alert-dismissable alert-' + this.weight,
16604 html: this.html || ''
16610 cfg.cls += ' alert-messages-fixed';
16624 onRender : function(ct, position)
16626 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16629 var cfg = Roo.apply({}, this.getAutoCreate());
16633 cfg.cls += ' ' + this.cls;
16636 cfg.style = this.style;
16638 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16640 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16643 this.el.select('>button.close').on('click', this.hide, this);
16649 if (!this.rendered) {
16655 this.fireEvent('show', this);
16661 if (!this.rendered) {
16667 this.fireEvent('hide', this);
16670 update : function()
16672 // var e = this.el.dom.firstChild;
16674 // if(this.closable){
16675 // e = e.nextSibling;
16678 // e.data = this.html || '';
16680 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';