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: '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
10474 * Create a new Container
10475 * @param {Object} config The config object
10480 Roo.bootstrap.Calendar = function(config){
10481 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10485 * Fires when a date is selected
10486 * @param {DatePicker} this
10487 * @param {Date} date The selected date
10491 * @event monthchange
10492 * Fires when the displayed month changes
10493 * @param {DatePicker} this
10494 * @param {Date} date The selected month
10496 'monthchange': true,
10498 * @event evententer
10499 * Fires when mouse over an event
10500 * @param {Calendar} this
10501 * @param {event} Event
10503 'evententer': true,
10505 * @event eventleave
10506 * Fires when the mouse leaves an
10507 * @param {Calendar} this
10510 'eventleave': true,
10512 * @event eventclick
10513 * Fires when the mouse click an
10514 * @param {Calendar} this
10523 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10526 * @cfg {Number} startDay
10527 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10533 getAutoCreate : function(){
10536 var fc_button = function(name, corner, style, content ) {
10537 return Roo.apply({},{
10539 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10541 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10544 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
10552 style : 'width:100%',
10559 cls : 'fc-header-left',
10561 fc_button('prev', 'left', 'arrow', '‹' ),
10562 fc_button('next', 'right', 'arrow', '›' ),
10563 { tag: 'span', cls: 'fc-header-space' },
10564 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
10572 cls : 'fc-header-center',
10576 cls: 'fc-header-title',
10579 html : 'month / year'
10587 cls : 'fc-header-right',
10589 /* fc_button('month', 'left', '', 'month' ),
10590 fc_button('week', '', '', 'week' ),
10591 fc_button('day', 'right', '', 'day' )
10603 var cal_heads = function() {
10605 // fixme - handle this.
10607 for (var i =0; i < Date.dayNames.length; i++) {
10608 var d = Date.dayNames[i];
10611 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
10612 html : d.substring(0,3)
10616 ret[0].cls += ' fc-first';
10617 ret[6].cls += ' fc-last';
10620 var cal_cell = function(n) {
10623 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10628 cls: 'fc-day-number',
10632 cls: 'fc-day-content',
10636 style: 'position: relative;' // height: 17px;
10648 var cal_rows = function() {
10651 for (var r = 0; r < 6; r++) {
10658 for (var i =0; i < Date.dayNames.length; i++) {
10659 var d = Date.dayNames[i];
10660 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10663 row.cn[0].cls+=' fc-first';
10664 row.cn[0].cn[0].style = 'min-height:90px';
10665 row.cn[6].cls+=' fc-last';
10669 ret[0].cls += ' fc-first';
10670 ret[4].cls += ' fc-prev-last';
10671 ret[5].cls += ' fc-last';
10678 cls: 'fc-border-separate',
10679 style : 'width:100%',
10687 cls : 'fc-first fc-last',
10705 cls : 'fc-content',
10706 style : "position: relative;",
10709 cls : 'fc-view fc-view-month fc-grid',
10710 style : 'position: relative',
10711 unselectable : 'on',
10714 cls : 'fc-event-container',
10715 style : 'position:absolute;z-index:8;top:0;left:0;'
10733 initEvents : function()
10736 throw "can not find store for calendar";
10742 style: "text-align:center",
10746 style: "background-color:white;width:50%;margin:250 auto",
10750 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10761 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10763 var size = this.el.select('.fc-content', true).first().getSize();
10764 this.maskEl.setSize(size.width, size.height);
10765 this.maskEl.enableDisplayMode("block");
10766 if(!this.loadMask){
10767 this.maskEl.hide();
10770 this.store = Roo.factory(this.store, Roo.data);
10771 this.store.on('load', this.onLoad, this);
10772 this.store.on('beforeload', this.onBeforeLoad, this);
10776 this.cells = this.el.select('.fc-day',true);
10777 //Roo.log(this.cells);
10778 this.textNodes = this.el.query('.fc-day-number');
10779 this.cells.addClassOnOver('fc-state-hover');
10781 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10782 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10783 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10784 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10786 this.on('monthchange', this.onMonthChange, this);
10788 this.update(new Date().clearTime());
10791 resize : function() {
10792 var sz = this.el.getSize();
10794 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10795 this.el.select('.fc-day-content div',true).setHeight(34);
10800 showPrevMonth : function(e){
10801 this.update(this.activeDate.add("mo", -1));
10803 showToday : function(e){
10804 this.update(new Date().clearTime());
10807 showNextMonth : function(e){
10808 this.update(this.activeDate.add("mo", 1));
10812 showPrevYear : function(){
10813 this.update(this.activeDate.add("y", -1));
10817 showNextYear : function(){
10818 this.update(this.activeDate.add("y", 1));
10823 update : function(date)
10825 var vd = this.activeDate;
10826 this.activeDate = date;
10827 // if(vd && this.el){
10828 // var t = date.getTime();
10829 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10830 // Roo.log('using add remove');
10832 // this.fireEvent('monthchange', this, date);
10834 // this.cells.removeClass("fc-state-highlight");
10835 // this.cells.each(function(c){
10836 // if(c.dateValue == t){
10837 // c.addClass("fc-state-highlight");
10838 // setTimeout(function(){
10839 // try{c.dom.firstChild.focus();}catch(e){}
10849 var days = date.getDaysInMonth();
10851 var firstOfMonth = date.getFirstDateOfMonth();
10852 var startingPos = firstOfMonth.getDay()-this.startDay;
10854 if(startingPos < this.startDay){
10858 var pm = date.add(Date.MONTH, -1);
10859 var prevStart = pm.getDaysInMonth()-startingPos;
10861 this.cells = this.el.select('.fc-day',true);
10862 this.textNodes = this.el.query('.fc-day-number');
10863 this.cells.addClassOnOver('fc-state-hover');
10865 var cells = this.cells.elements;
10866 var textEls = this.textNodes;
10868 Roo.each(cells, function(cell){
10869 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10872 days += startingPos;
10874 // convert everything to numbers so it's fast
10875 var day = 86400000;
10876 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10879 //Roo.log(prevStart);
10881 var today = new Date().clearTime().getTime();
10882 var sel = date.clearTime().getTime();
10883 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10884 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10885 var ddMatch = this.disabledDatesRE;
10886 var ddText = this.disabledDatesText;
10887 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10888 var ddaysText = this.disabledDaysText;
10889 var format = this.format;
10891 var setCellClass = function(cal, cell){
10893 //Roo.log('set Cell Class');
10895 var t = d.getTime();
10899 cell.dateValue = t;
10901 cell.className += " fc-today";
10902 cell.className += " fc-state-highlight";
10903 cell.title = cal.todayText;
10906 // disable highlight in other month..
10907 //cell.className += " fc-state-highlight";
10912 cell.className = " fc-state-disabled";
10913 cell.title = cal.minText;
10917 cell.className = " fc-state-disabled";
10918 cell.title = cal.maxText;
10922 if(ddays.indexOf(d.getDay()) != -1){
10923 cell.title = ddaysText;
10924 cell.className = " fc-state-disabled";
10927 if(ddMatch && format){
10928 var fvalue = d.dateFormat(format);
10929 if(ddMatch.test(fvalue)){
10930 cell.title = ddText.replace("%0", fvalue);
10931 cell.className = " fc-state-disabled";
10935 if (!cell.initialClassName) {
10936 cell.initialClassName = cell.dom.className;
10939 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10944 for(; i < startingPos; i++) {
10945 textEls[i].innerHTML = (++prevStart);
10946 d.setDate(d.getDate()+1);
10948 cells[i].className = "fc-past fc-other-month";
10949 setCellClass(this, cells[i]);
10954 for(; i < days; i++){
10955 intDay = i - startingPos + 1;
10956 textEls[i].innerHTML = (intDay);
10957 d.setDate(d.getDate()+1);
10959 cells[i].className = ''; // "x-date-active";
10960 setCellClass(this, cells[i]);
10964 for(; i < 42; i++) {
10965 textEls[i].innerHTML = (++extraDays);
10966 d.setDate(d.getDate()+1);
10968 cells[i].className = "fc-future fc-other-month";
10969 setCellClass(this, cells[i]);
10972 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10974 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10976 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10977 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10979 if(totalRows != 6){
10980 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10981 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10984 this.fireEvent('monthchange', this, date);
10988 if(!this.internalRender){
10989 var main = this.el.dom.firstChild;
10990 var w = main.offsetWidth;
10991 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10992 Roo.fly(main).setWidth(w);
10993 this.internalRender = true;
10994 // opera does not respect the auto grow header center column
10995 // then, after it gets a width opera refuses to recalculate
10996 // without a second pass
10997 if(Roo.isOpera && !this.secondPass){
10998 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10999 this.secondPass = true;
11000 this.update.defer(10, this, [date]);
11007 findCell : function(dt) {
11008 dt = dt.clearTime().getTime();
11010 this.cells.each(function(c){
11011 //Roo.log("check " +c.dateValue + '?=' + dt);
11012 if(c.dateValue == dt){
11022 findCells : function(ev) {
11023 var s = ev.start.clone().clearTime().getTime();
11025 var e= ev.end.clone().clearTime().getTime();
11028 this.cells.each(function(c){
11029 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11031 if(c.dateValue > e){
11034 if(c.dateValue < s){
11043 findBestRow: function(cells)
11047 for (var i =0 ; i < cells.length;i++) {
11048 ret = Math.max(cells[i].rows || 0,ret);
11055 addItem : function(ev)
11057 // look for vertical location slot in
11058 var cells = this.findCells(ev);
11060 ev.row = this.findBestRow(cells);
11062 // work out the location.
11066 for(var i =0; i < cells.length; i++) {
11074 if (crow.start.getY() == cells[i].getY()) {
11076 crow.end = cells[i];
11092 for (var i = 0; i < cells.length;i++) {
11093 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11097 this.calevents.push(ev);
11100 clearEvents: function() {
11102 if(!this.calevents){
11106 Roo.each(this.cells.elements, function(c){
11110 Roo.each(this.calevents, function(e) {
11111 Roo.each(e.els, function(el) {
11112 el.un('mouseenter' ,this.onEventEnter, this);
11113 el.un('mouseleave' ,this.onEventLeave, this);
11120 renderEvents: function()
11122 // first make sure there is enough space..
11124 this.cells.each(function(c) {
11126 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
11129 for (var e = 0; e < this.calevents.length; e++) {
11130 var ev = this.calevents[e];
11131 var cells = ev.cells;
11132 var rows = ev.rows;
11134 for(var i =0; i < rows.length; i++) {
11137 // how many rows should it span..
11140 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11141 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11143 unselectable : "on",
11146 cls: 'fc-event-inner',
11150 // cls: 'fc-event-time',
11151 // html : cells.length > 1 ? '' : ev.time
11155 cls: 'fc-event-title',
11156 html : String.format('{0}', ev.title)
11163 cls: 'ui-resizable-handle ui-resizable-e',
11164 html : '  '
11170 cfg.cls += ' fc-event-start';
11172 if ((i+1) == rows.length) {
11173 cfg.cls += ' fc-event-end';
11176 var ctr = this.el.select('.fc-event-container',true).first();
11177 var cg = ctr.createChild(cfg);
11179 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11180 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11181 cg.on('click', this.onEventClick, this, ev);
11185 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11186 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11188 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11189 cg.setWidth(ebox.right - sbox.x -2);
11197 onEventEnter: function (e, el,event,d) {
11198 this.fireEvent('evententer', this, el, event);
11201 onEventLeave: function (e, el,event,d) {
11202 this.fireEvent('eventleave', this, el, event);
11205 onEventClick: function (e, el,event,d) {
11206 this.fireEvent('eventclick', this, el, event);
11209 onMonthChange: function () {
11213 onLoad: function ()
11215 this.calevents = [];
11218 if(this.store.getCount() > 0){
11219 this.store.data.each(function(d){
11222 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11223 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11224 time : d.data.start_time,
11225 title : d.data.title,
11226 description : d.data.description,
11227 venue : d.data.venue
11232 this.renderEvents();
11235 this.maskEl.hide();
11239 onBeforeLoad: function()
11241 this.clearEvents();
11244 this.maskEl.show();
11258 * @class Roo.bootstrap.Popover
11259 * @extends Roo.bootstrap.Component
11260 * Bootstrap Popover class
11261 * @cfg {String} html contents of the popover (or false to use children..)
11262 * @cfg {String} title of popover (or false to hide)
11263 * @cfg {String} placement how it is placed
11264 * @cfg {String} trigger click || hover (or false to trigger manually)
11265 * @cfg {String} over what (parent or false to trigger manually.)
11268 * Create a new Popover
11269 * @param {Object} config The config object
11272 Roo.bootstrap.Popover = function(config){
11273 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11276 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11278 title: 'Fill in a title',
11281 placement : 'right',
11282 trigger : 'hover', // hover
11286 can_build_overlaid : false,
11288 getChildContainer : function()
11290 return this.el.select('.popover-content',true).first();
11293 getAutoCreate : function(){
11294 Roo.log('make popover?');
11296 cls : 'popover roo-dynamic',
11297 style: 'display:block',
11303 cls : 'popover-inner',
11307 cls: 'popover-title',
11311 cls : 'popover-content',
11322 setTitle: function(str)
11324 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11326 setContent: function(str)
11328 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11330 // as it get's added to the bottom of the page.
11331 onRender : function(ct, position)
11333 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11335 var cfg = Roo.apply({}, this.getAutoCreate());
11339 cfg.cls += ' ' + this.cls;
11342 cfg.style = this.style;
11344 Roo.log("adding to ")
11345 this.el = Roo.get(document.body).createChild(cfg, position);
11351 initEvents : function()
11353 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11354 this.el.enableDisplayMode('block');
11356 if (this.over === false) {
11359 if (this.triggers === false) {
11362 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11363 var triggers = this.trigger ? this.trigger.split(' ') : [];
11364 Roo.each(triggers, function(trigger) {
11366 if (trigger == 'click') {
11367 on_el.on('click', this.toggle, this);
11368 } else if (trigger != 'manual') {
11369 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11370 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11372 on_el.on(eventIn ,this.enter, this);
11373 on_el.on(eventOut, this.leave, this);
11384 toggle : function () {
11385 this.hoverState == 'in' ? this.leave() : this.enter();
11388 enter : function () {
11391 clearTimeout(this.timeout);
11393 this.hoverState = 'in'
11395 if (!this.delay || !this.delay.show) {
11400 this.timeout = setTimeout(function () {
11401 if (_t.hoverState == 'in') {
11404 }, this.delay.show)
11406 leave : function() {
11407 clearTimeout(this.timeout);
11409 this.hoverState = 'out'
11411 if (!this.delay || !this.delay.hide) {
11416 this.timeout = setTimeout(function () {
11417 if (_t.hoverState == 'out') {
11420 }, this.delay.hide)
11423 show : function (on_el)
11426 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11429 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11430 if (this.html !== false) {
11431 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11433 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11434 if (!this.title.length) {
11435 this.el.select('.popover-title',true).hide();
11438 var placement = typeof this.placement == 'function' ?
11439 this.placement.call(this, this.el, on_el) :
11442 var autoToken = /\s?auto?\s?/i;
11443 var autoPlace = autoToken.test(placement);
11445 placement = placement.replace(autoToken, '') || 'top';
11449 //this.el.setXY([0,0]);
11451 this.el.dom.style.display='block';
11452 this.el.addClass(placement);
11454 //this.el.appendTo(on_el);
11456 var p = this.getPosition();
11457 var box = this.el.getBox();
11462 var align = Roo.bootstrap.Popover.alignment[placement]
11463 this.el.alignTo(on_el, align[0],align[1]);
11464 //var arrow = this.el.select('.arrow',true).first();
11465 //arrow.set(align[2],
11467 this.el.addClass('in');
11468 this.hoverState = null;
11470 if (this.el.hasClass('fade')) {
11477 this.el.setXY([0,0]);
11478 this.el.removeClass('in');
11485 Roo.bootstrap.Popover.alignment = {
11486 'left' : ['r-l', [-10,0], 'right'],
11487 'right' : ['l-r', [10,0], 'left'],
11488 'bottom' : ['t-b', [0,10], 'top'],
11489 'top' : [ 'b-t', [0,-10], 'bottom']
11500 * @class Roo.bootstrap.Progress
11501 * @extends Roo.bootstrap.Component
11502 * Bootstrap Progress class
11503 * @cfg {Boolean} striped striped of the progress bar
11504 * @cfg {Boolean} active animated of the progress bar
11508 * Create a new Progress
11509 * @param {Object} config The config object
11512 Roo.bootstrap.Progress = function(config){
11513 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
11516 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
11521 getAutoCreate : function(){
11529 cfg.cls += ' progress-striped';
11533 cfg.cls += ' active';
11552 * @class Roo.bootstrap.ProgressBar
11553 * @extends Roo.bootstrap.Component
11554 * Bootstrap ProgressBar class
11555 * @cfg {Number} aria_valuenow aria-value now
11556 * @cfg {Number} aria_valuemin aria-value min
11557 * @cfg {Number} aria_valuemax aria-value max
11558 * @cfg {String} label label for the progress bar
11559 * @cfg {String} panel (success | info | warning | danger )
11560 * @cfg {String} role role of the progress bar
11561 * @cfg {String} sr_only text
11565 * Create a new ProgressBar
11566 * @param {Object} config The config object
11569 Roo.bootstrap.ProgressBar = function(config){
11570 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
11573 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
11577 aria_valuemax : 100,
11583 getAutoCreate : function()
11588 cls: 'progress-bar',
11589 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
11601 cfg.role = this.role;
11604 if(this.aria_valuenow){
11605 cfg['aria-valuenow'] = this.aria_valuenow;
11608 if(this.aria_valuemin){
11609 cfg['aria-valuemin'] = this.aria_valuemin;
11612 if(this.aria_valuemax){
11613 cfg['aria-valuemax'] = this.aria_valuemax;
11616 if(this.label && !this.sr_only){
11617 cfg.html = this.label;
11621 cfg.cls += ' progress-bar-' + this.panel;
11627 update : function(aria_valuenow)
11629 this.aria_valuenow = aria_valuenow;
11631 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11646 * @class Roo.bootstrap.TabPanel
11647 * @extends Roo.bootstrap.Component
11648 * Bootstrap TabPanel class
11649 * @cfg {Boolean} active panel active
11650 * @cfg {String} html panel content
11651 * @cfg {String} tabId tab relate id
11652 * @cfg {String} navId The navbar which triggers show hide
11656 * Create a new TabPanel
11657 * @param {Object} config The config object
11660 Roo.bootstrap.TabPanel = function(config){
11661 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11665 * Fires when the active status changes
11666 * @param {Roo.bootstrap.TabPanel} this
11667 * @param {Boolean} state the new state
11674 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11681 getAutoCreate : function(){
11685 html: this.html || ''
11689 cfg.cls += ' active';
11693 cfg.tabId = this.tabId;
11698 onRender : function(ct, position)
11700 // Roo.log("Call onRender: " + this.xtype);
11702 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11704 if (this.navId && this.tabId) {
11705 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11707 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11709 item.on('changed', function(item, state) {
11710 this.setActive(state);
11716 setActive: function(state)
11718 Roo.log("panel - set active " + this.tabId + "=" + state);
11720 this.active = state;
11722 this.el.removeClass('active');
11724 } else if (!this.el.hasClass('active')) {
11725 this.el.addClass('active');
11727 this.fireEvent('changed', this, state);
11744 * @class Roo.bootstrap.DateField
11745 * @extends Roo.bootstrap.Input
11746 * Bootstrap DateField class
11747 * @cfg {Number} weekStart default 0
11748 * @cfg {Number} weekStart default 0
11749 * @cfg {Number} viewMode default empty, (months|years)
11750 * @cfg {Number} minViewMode default empty, (months|years)
11751 * @cfg {Number} startDate default -Infinity
11752 * @cfg {Number} endDate default Infinity
11753 * @cfg {Boolean} todayHighlight default false
11754 * @cfg {Boolean} todayBtn default false
11755 * @cfg {Boolean} calendarWeeks default false
11756 * @cfg {Object} daysOfWeekDisabled default empty
11758 * @cfg {Boolean} keyboardNavigation default true
11759 * @cfg {String} language default en
11762 * Create a new DateField
11763 * @param {Object} config The config object
11766 Roo.bootstrap.DateField = function(config){
11767 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
11771 * Fires when this field show.
11772 * @param {Roo.bootstrap.DateField} this
11773 * @param {Mixed} date The date value
11778 * Fires when this field hide.
11779 * @param {Roo.bootstrap.DateField} this
11780 * @param {Mixed} date The date value
11785 * Fires when select a date.
11786 * @param {Roo.bootstrap.DateField} this
11787 * @param {Mixed} date The date value
11793 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11796 * @cfg {String} format
11797 * The default date format string which can be overriden for localization support. The format must be
11798 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11802 * @cfg {String} altFormats
11803 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11804 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11806 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11814 todayHighlight : false,
11820 keyboardNavigation: true,
11822 calendarWeeks: false,
11824 startDate: -Infinity,
11828 daysOfWeekDisabled: [],
11832 UTCDate: function()
11834 return new Date(Date.UTC.apply(Date, arguments));
11837 UTCToday: function()
11839 var today = new Date();
11840 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11843 getDate: function() {
11844 var d = this.getUTCDate();
11845 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11848 getUTCDate: function() {
11852 setDate: function(d) {
11853 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11856 setUTCDate: function(d) {
11858 this.setValue(this.formatDate(this.date));
11861 onRender: function(ct, position)
11864 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11866 this.language = this.language || 'en';
11867 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11868 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11870 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11871 this.format = this.format || 'm/d/y';
11872 this.isInline = false;
11873 this.isInput = true;
11874 this.component = this.el.select('.add-on', true).first() || false;
11875 this.component = (this.component && this.component.length === 0) ? false : this.component;
11876 this.hasInput = this.component && this.inputEL().length;
11878 if (typeof(this.minViewMode === 'string')) {
11879 switch (this.minViewMode) {
11881 this.minViewMode = 1;
11884 this.minViewMode = 2;
11887 this.minViewMode = 0;
11892 if (typeof(this.viewMode === 'string')) {
11893 switch (this.viewMode) {
11906 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11908 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11910 this.picker().on('mousedown', this.onMousedown, this);
11911 this.picker().on('click', this.onClick, this);
11913 this.picker().addClass('datepicker-dropdown');
11915 this.startViewMode = this.viewMode;
11918 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11919 if(!this.calendarWeeks){
11924 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11925 v.attr('colspan', function(i, val){
11926 return parseInt(val) + 1;
11931 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11933 this.setStartDate(this.startDate);
11934 this.setEndDate(this.endDate);
11936 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11943 if(this.isInline) {
11948 picker : function()
11950 return this.el.select('.datepicker', true).first();
11953 fillDow: function()
11955 var dowCnt = this.weekStart;
11964 if(this.calendarWeeks){
11972 while (dowCnt < this.weekStart + 7) {
11976 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11980 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11983 fillMonths: function()
11986 var months = this.picker().select('>.datepicker-months td', true).first();
11988 months.dom.innerHTML = '';
11994 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
11997 months.createChild(month);
12002 update: function(){
12004 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12006 if (this.date < this.startDate) {
12007 this.viewDate = new Date(this.startDate);
12008 } else if (this.date > this.endDate) {
12009 this.viewDate = new Date(this.endDate);
12011 this.viewDate = new Date(this.date);
12018 var d = new Date(this.viewDate),
12019 year = d.getUTCFullYear(),
12020 month = d.getUTCMonth(),
12021 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12022 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12023 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12024 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12025 currentDate = this.date && this.date.valueOf(),
12026 today = this.UTCToday();
12028 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12030 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12032 // this.picker.select('>tfoot th.today').
12033 // .text(dates[this.language].today)
12034 // .toggle(this.todayBtn !== false);
12036 this.updateNavArrows();
12039 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12041 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12043 prevMonth.setUTCDate(day);
12045 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12047 var nextMonth = new Date(prevMonth);
12049 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12051 nextMonth = nextMonth.valueOf();
12053 var fillMonths = false;
12055 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12057 while(prevMonth.valueOf() < nextMonth) {
12060 if (prevMonth.getUTCDay() === this.weekStart) {
12062 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12070 if(this.calendarWeeks){
12071 // ISO 8601: First week contains first thursday.
12072 // ISO also states week starts on Monday, but we can be more abstract here.
12074 // Start of current week: based on weekstart/current date
12075 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12076 // Thursday of this week
12077 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12078 // First Thursday of year, year from thursday
12079 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12080 // Calendar week: ms between thursdays, div ms per day, div 7 days
12081 calWeek = (th - yth) / 864e5 / 7 + 1;
12083 fillMonths.cn.push({
12091 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12093 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12096 if (this.todayHighlight &&
12097 prevMonth.getUTCFullYear() == today.getFullYear() &&
12098 prevMonth.getUTCMonth() == today.getMonth() &&
12099 prevMonth.getUTCDate() == today.getDate()) {
12100 clsName += ' today';
12103 if (currentDate && prevMonth.valueOf() === currentDate) {
12104 clsName += ' active';
12107 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12108 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12109 clsName += ' disabled';
12112 fillMonths.cn.push({
12114 cls: 'day ' + clsName,
12115 html: prevMonth.getDate()
12118 prevMonth.setDate(prevMonth.getDate()+1);
12121 var currentYear = this.date && this.date.getUTCFullYear();
12122 var currentMonth = this.date && this.date.getUTCMonth();
12124 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12126 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12127 v.removeClass('active');
12129 if(currentYear === year && k === currentMonth){
12130 v.addClass('active');
12133 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12134 v.addClass('disabled');
12140 year = parseInt(year/10, 10) * 10;
12142 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12144 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12147 for (var i = -1; i < 11; i++) {
12148 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12150 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12158 showMode: function(dir) {
12160 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12162 Roo.each(this.picker().select('>div',true).elements, function(v){
12163 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12166 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12171 if(this.isInline) return;
12173 this.picker().removeClass(['bottom', 'top']);
12175 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12177 * place to the top of element!
12181 this.picker().addClass('top');
12182 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12187 this.picker().addClass('bottom');
12189 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12192 parseDate : function(value){
12193 if(!value || value instanceof Date){
12196 var v = Date.parseDate(value, this.format);
12197 if (!v && this.useIso) {
12198 v = Date.parseDate(value, 'Y-m-d');
12200 if(!v && this.altFormats){
12201 if(!this.altFormatsArray){
12202 this.altFormatsArray = this.altFormats.split("|");
12204 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12205 v = Date.parseDate(value, this.altFormatsArray[i]);
12211 formatDate : function(date, fmt){
12212 return (!date || !(date instanceof Date)) ?
12213 date : date.dateFormat(fmt || this.format);
12216 onFocus : function()
12218 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12222 onBlur : function()
12224 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12230 this.picker().show();
12234 this.fireEvent('show', this, this.date);
12239 if(this.isInline) return;
12240 this.picker().hide();
12241 this.viewMode = this.startViewMode;
12244 this.fireEvent('hide', this, this.date);
12248 onMousedown: function(e){
12249 e.stopPropagation();
12250 e.preventDefault();
12253 keyup: function(e){
12254 Roo.bootstrap.DateField.superclass.keyup.call(this);
12259 setValue: function(v){
12260 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12262 this.fireEvent('select', this, this.date);
12266 fireKey: function(e){
12267 if (!this.picker().isVisible()){
12268 if (e.keyCode == 27) // allow escape to hide and re-show picker
12272 var dateChanged = false,
12274 newDate, newViewDate;
12278 e.preventDefault();
12282 if (!this.keyboardNavigation) break;
12283 dir = e.keyCode == 37 ? -1 : 1;
12286 newDate = this.moveYear(this.date, dir);
12287 newViewDate = this.moveYear(this.viewDate, dir);
12288 } else if (e.shiftKey){
12289 newDate = this.moveMonth(this.date, dir);
12290 newViewDate = this.moveMonth(this.viewDate, dir);
12292 newDate = new Date(this.date);
12293 newDate.setUTCDate(this.date.getUTCDate() + dir);
12294 newViewDate = new Date(this.viewDate);
12295 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12297 if (this.dateWithinRange(newDate)){
12298 this.date = newDate;
12299 this.viewDate = newViewDate;
12300 this.setValue(this.formatDate(this.date));
12302 e.preventDefault();
12303 dateChanged = true;
12308 if (!this.keyboardNavigation) break;
12309 dir = e.keyCode == 38 ? -1 : 1;
12311 newDate = this.moveYear(this.date, dir);
12312 newViewDate = this.moveYear(this.viewDate, dir);
12313 } else if (e.shiftKey){
12314 newDate = this.moveMonth(this.date, dir);
12315 newViewDate = this.moveMonth(this.viewDate, dir);
12317 newDate = new Date(this.date);
12318 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12319 newViewDate = new Date(this.viewDate);
12320 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12322 if (this.dateWithinRange(newDate)){
12323 this.date = newDate;
12324 this.viewDate = newViewDate;
12325 this.setValue(this.formatDate(this.date));
12327 e.preventDefault();
12328 dateChanged = true;
12332 this.setValue(this.formatDate(this.date));
12334 e.preventDefault();
12337 this.setValue(this.formatDate(this.date));
12344 onClick: function(e) {
12345 e.stopPropagation();
12346 e.preventDefault();
12348 var target = e.getTarget();
12350 if(target.nodeName.toLowerCase() === 'i'){
12351 target = Roo.get(target).dom.parentNode;
12354 var nodeName = target.nodeName;
12355 var className = target.className;
12356 var html = target.innerHTML;
12358 switch(nodeName.toLowerCase()) {
12360 switch(className) {
12366 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12367 switch(this.viewMode){
12369 this.viewDate = this.moveMonth(this.viewDate, dir);
12373 this.viewDate = this.moveYear(this.viewDate, dir);
12379 var date = new Date();
12380 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12382 this.setValue(this.formatDate(this.date));
12388 if (className.indexOf('disabled') === -1) {
12389 this.viewDate.setUTCDate(1);
12390 if (className.indexOf('month') !== -1) {
12391 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12393 var year = parseInt(html, 10) || 0;
12394 this.viewDate.setUTCFullYear(year);
12403 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12404 var day = parseInt(html, 10) || 1;
12405 var year = this.viewDate.getUTCFullYear(),
12406 month = this.viewDate.getUTCMonth();
12408 if (className.indexOf('old') !== -1) {
12415 } else if (className.indexOf('new') !== -1) {
12423 this.date = this.UTCDate(year, month, day,0,0,0,0);
12424 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12426 this.setValue(this.formatDate(this.date));
12433 setStartDate: function(startDate){
12434 this.startDate = startDate || -Infinity;
12435 if (this.startDate !== -Infinity) {
12436 this.startDate = this.parseDate(this.startDate);
12439 this.updateNavArrows();
12442 setEndDate: function(endDate){
12443 this.endDate = endDate || Infinity;
12444 if (this.endDate !== Infinity) {
12445 this.endDate = this.parseDate(this.endDate);
12448 this.updateNavArrows();
12451 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
12452 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
12453 if (typeof(this.daysOfWeekDisabled) !== 'object') {
12454 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
12456 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
12457 return parseInt(d, 10);
12460 this.updateNavArrows();
12463 updateNavArrows: function() {
12464 var d = new Date(this.viewDate),
12465 year = d.getUTCFullYear(),
12466 month = d.getUTCMonth();
12468 Roo.each(this.picker().select('.prev', true).elements, function(v){
12470 switch (this.viewMode) {
12473 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
12479 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
12486 Roo.each(this.picker().select('.next', true).elements, function(v){
12488 switch (this.viewMode) {
12491 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
12497 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
12505 moveMonth: function(date, dir){
12506 if (!dir) return date;
12507 var new_date = new Date(date.valueOf()),
12508 day = new_date.getUTCDate(),
12509 month = new_date.getUTCMonth(),
12510 mag = Math.abs(dir),
12512 dir = dir > 0 ? 1 : -1;
12515 // If going back one month, make sure month is not current month
12516 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
12518 return new_date.getUTCMonth() == month;
12520 // If going forward one month, make sure month is as expected
12521 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
12523 return new_date.getUTCMonth() != new_month;
12525 new_month = month + dir;
12526 new_date.setUTCMonth(new_month);
12527 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
12528 if (new_month < 0 || new_month > 11)
12529 new_month = (new_month + 12) % 12;
12531 // For magnitudes >1, move one month at a time...
12532 for (var i=0; i<mag; i++)
12533 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
12534 new_date = this.moveMonth(new_date, dir);
12535 // ...then reset the day, keeping it in the new month
12536 new_month = new_date.getUTCMonth();
12537 new_date.setUTCDate(day);
12539 return new_month != new_date.getUTCMonth();
12542 // Common date-resetting loop -- if date is beyond end of month, make it
12545 new_date.setUTCDate(--day);
12546 new_date.setUTCMonth(new_month);
12551 moveYear: function(date, dir){
12552 return this.moveMonth(date, dir*12);
12555 dateWithinRange: function(date){
12556 return date >= this.startDate && date <= this.endDate;
12560 remove: function() {
12561 this.picker().remove();
12566 Roo.apply(Roo.bootstrap.DateField, {
12577 html: '<i class="icon-arrow-left"/>'
12587 html: '<i class="icon-arrow-right"/>'
12629 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12630 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12631 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12632 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12633 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12646 navFnc: 'FullYear',
12651 navFnc: 'FullYear',
12656 Roo.apply(Roo.bootstrap.DateField, {
12660 cls: 'datepicker dropdown-menu',
12664 cls: 'datepicker-days',
12668 cls: 'table-condensed',
12670 Roo.bootstrap.DateField.head,
12674 Roo.bootstrap.DateField.footer
12681 cls: 'datepicker-months',
12685 cls: 'table-condensed',
12687 Roo.bootstrap.DateField.head,
12688 Roo.bootstrap.DateField.content,
12689 Roo.bootstrap.DateField.footer
12696 cls: 'datepicker-years',
12700 cls: 'table-condensed',
12702 Roo.bootstrap.DateField.head,
12703 Roo.bootstrap.DateField.content,
12704 Roo.bootstrap.DateField.footer
12723 * @class Roo.bootstrap.TimeField
12724 * @extends Roo.bootstrap.Input
12725 * Bootstrap DateField class
12729 * Create a new TimeField
12730 * @param {Object} config The config object
12733 Roo.bootstrap.TimeField = function(config){
12734 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12738 * Fires when this field show.
12739 * @param {Roo.bootstrap.DateField} this
12740 * @param {Mixed} date The date value
12745 * Fires when this field hide.
12746 * @param {Roo.bootstrap.DateField} this
12747 * @param {Mixed} date The date value
12752 * Fires when select a date.
12753 * @param {Roo.bootstrap.DateField} this
12754 * @param {Mixed} date The date value
12760 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
12763 * @cfg {String} format
12764 * The default time format string which can be overriden for localization support. The format must be
12765 * valid according to {@link Date#parseDate} (defaults to 'H:i').
12769 onRender: function(ct, position)
12772 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
12774 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
12776 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12778 this.pop = this.picker().select('>.datepicker-time',true).first();
12779 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12781 this.picker().on('mousedown', this.onMousedown, this);
12782 this.picker().on('click', this.onClick, this);
12784 this.picker().addClass('datepicker-dropdown');
12789 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12790 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12791 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12792 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12793 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12794 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12798 fireKey: function(e){
12799 if (!this.picker().isVisible()){
12800 if (e.keyCode == 27) // allow escape to hide and re-show picker
12805 e.preventDefault();
12813 this.onTogglePeriod();
12816 this.onIncrementMinutes();
12819 this.onDecrementMinutes();
12828 onClick: function(e) {
12829 e.stopPropagation();
12830 e.preventDefault();
12833 picker : function()
12835 return this.el.select('.datepicker', true).first();
12838 fillTime: function()
12840 var time = this.pop.select('tbody', true).first();
12842 time.dom.innerHTML = '';
12857 cls: 'hours-up glyphicon glyphicon-chevron-up'
12877 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12898 cls: 'timepicker-hour',
12913 cls: 'timepicker-minute',
12928 cls: 'btn btn-primary period',
12950 cls: 'hours-down glyphicon glyphicon-chevron-down'
12970 cls: 'minutes-down glyphicon glyphicon-chevron-down'
12988 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
12995 var hours = this.time.getHours();
12996 var minutes = this.time.getMinutes();
13009 hours = hours - 12;
13013 hours = '0' + hours;
13017 minutes = '0' + minutes;
13020 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13021 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13022 this.pop.select('button', true).first().dom.innerHTML = period;
13028 this.picker().removeClass(['bottom', 'top']);
13030 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13032 * place to the top of element!
13036 this.picker().addClass('top');
13037 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13042 this.picker().addClass('bottom');
13044 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13047 onFocus : function()
13049 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13053 onBlur : function()
13055 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13061 this.picker().show();
13066 this.fireEvent('show', this, this.date);
13071 this.picker().hide();
13074 this.fireEvent('hide', this, this.date);
13077 setTime : function()
13080 this.setValue(this.time.format(this.format));
13082 this.fireEvent('select', this, this.date);
13087 onMousedown: function(e){
13088 e.stopPropagation();
13089 e.preventDefault();
13092 onIncrementHours: function()
13094 Roo.log('onIncrementHours');
13095 this.time = this.time.add(Date.HOUR, 1);
13100 onDecrementHours: function()
13102 Roo.log('onDecrementHours');
13103 this.time = this.time.add(Date.HOUR, -1);
13107 onIncrementMinutes: function()
13109 Roo.log('onIncrementMinutes');
13110 this.time = this.time.add(Date.MINUTE, 1);
13114 onDecrementMinutes: function()
13116 Roo.log('onDecrementMinutes');
13117 this.time = this.time.add(Date.MINUTE, -1);
13121 onTogglePeriod: function()
13123 Roo.log('onTogglePeriod');
13124 this.time = this.time.add(Date.HOUR, 12);
13131 Roo.apply(Roo.bootstrap.TimeField, {
13161 cls: 'btn btn-info ok',
13173 Roo.apply(Roo.bootstrap.TimeField, {
13177 cls: 'datepicker dropdown-menu',
13181 cls: 'datepicker-time',
13185 cls: 'table-condensed',
13187 Roo.bootstrap.TimeField.content,
13188 Roo.bootstrap.TimeField.footer
13207 * @class Roo.bootstrap.CheckBox
13208 * @extends Roo.bootstrap.Input
13209 * Bootstrap CheckBox class
13211 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13212 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13213 * @cfg {String} boxLabel The text that appears beside the checkbox
13214 * @cfg {Boolean} checked initnal the element
13217 * Create a new CheckBox
13218 * @param {Object} config The config object
13221 Roo.bootstrap.CheckBox = function(config){
13222 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13227 * Fires when the element is checked or unchecked.
13228 * @param {Roo.bootstrap.CheckBox} this This input
13229 * @param {Boolean} checked The new checked value
13235 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13237 inputType: 'checkbox',
13243 getAutoCreate : function()
13245 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13251 cfg.cls = 'form-group' //input-group
13256 type : this.inputType,
13257 value : (!this.checked) ? this.valueOff : this.inputValue,
13259 placeholder : this.placeholder || ''
13263 if (this.disabled) {
13264 input.disabled=true;
13268 input.checked = this.checked;
13272 input.name = this.name;
13276 input.cls += ' input-' + this.size;
13280 ['xs','sm','md','lg'].map(function(size){
13281 if (settings[size]) {
13282 cfg.cls += ' col-' + size + '-' + settings[size];
13286 var inputblock = input;
13288 if (this.before || this.after) {
13291 cls : 'input-group',
13295 inputblock.cn.push({
13297 cls : 'input-group-addon',
13301 inputblock.cn.push(input);
13303 inputblock.cn.push({
13305 cls : 'input-group-addon',
13312 if (align ==='left' && this.fieldLabel.length) {
13313 Roo.log("left and has label");
13319 cls : 'control-label col-md-' + this.labelWidth,
13320 html : this.fieldLabel
13324 cls : "col-md-" + (12 - this.labelWidth),
13331 } else if ( this.fieldLabel.length) {
13336 tag: this.boxLabel ? 'span' : 'label',
13338 cls: 'control-label box-input-label',
13339 //cls : 'input-group-addon',
13340 html : this.fieldLabel
13350 Roo.log(" no label && no align");
13365 html: this.boxLabel
13374 * return the real input element.
13376 inputEl: function ()
13378 return this.el.select('input.form-box',true).first();
13381 initEvents : function()
13383 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13385 this.inputEl().on('click', this.onClick, this);
13389 onClick : function()
13391 this.setChecked(!this.checked);
13394 setChecked : function(state,suppressEvent)
13396 this.checked = state;
13398 this.inputEl().dom.checked = state;
13400 if(suppressEvent !== true){
13401 this.fireEvent('check', this, state);
13404 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13408 setValue : function(v,suppressEvent)
13410 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
13424 * @class Roo.bootstrap.Radio
13425 * @extends Roo.bootstrap.CheckBox
13426 * Bootstrap Radio class
13429 * Create a new Radio
13430 * @param {Object} config The config object
13433 Roo.bootstrap.Radio = function(config){
13434 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
13438 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
13440 inputType: 'radio',
13444 getAutoCreate : function()
13446 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13452 cfg.cls = 'form-group' //input-group
13457 type : this.inputType,
13458 value : (!this.checked) ? this.valueOff : this.inputValue,
13460 placeholder : this.placeholder || ''
13464 if (this.disabled) {
13465 input.disabled=true;
13469 input.checked = this.checked;
13473 input.name = this.name;
13477 input.cls += ' input-' + this.size;
13481 ['xs','sm','md','lg'].map(function(size){
13482 if (settings[size]) {
13483 cfg.cls += ' col-' + size + '-' + settings[size];
13487 var inputblock = input;
13489 if (this.before || this.after) {
13492 cls : 'input-group',
13496 inputblock.cn.push({
13498 cls : 'input-group-addon',
13502 inputblock.cn.push(input);
13504 inputblock.cn.push({
13506 cls : 'input-group-addon',
13513 if (align ==='left' && this.fieldLabel.length) {
13514 Roo.log("left and has label");
13520 cls : 'control-label col-md-' + this.labelWidth,
13521 html : this.fieldLabel
13525 cls : "col-md-" + (12 - this.labelWidth),
13532 } else if ( this.fieldLabel.length) {
13539 cls: 'control-label box-input-label',
13540 //cls : 'input-group-addon',
13541 html : this.fieldLabel
13551 Roo.log(" no label && no align");
13566 html: this.boxLabel
13574 onClick : function()
13576 this.setChecked(true);
13579 setChecked : function(state,suppressEvent)
13582 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13583 v.dom.checked = false;
13587 this.checked = state;
13588 this.inputEl().dom.checked = state;
13590 if(suppressEvent !== true){
13591 this.fireEvent('check', this, state);
13594 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13598 getGroupValue : function()
13601 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13602 if(v.dom.checked == true){
13603 value = v.dom.value;
13611 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
13612 * @return {Mixed} value The field value
13614 getValue : function(){
13615 return this.getGroupValue();
13621 //<script type="text/javascript">
13624 * Based Ext JS Library 1.1.1
13625 * Copyright(c) 2006-2007, Ext JS, LLC.
13631 * @class Roo.HtmlEditorCore
13632 * @extends Roo.Component
13633 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13635 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13638 Roo.HtmlEditorCore = function(config){
13641 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13644 * @event initialize
13645 * Fires when the editor is fully initialized (including the iframe)
13646 * @param {Roo.HtmlEditorCore} this
13651 * Fires when the editor is first receives the focus. Any insertion must wait
13652 * until after this event.
13653 * @param {Roo.HtmlEditorCore} this
13657 * @event beforesync
13658 * Fires before the textarea is updated with content from the editor iframe. Return false
13659 * to cancel the sync.
13660 * @param {Roo.HtmlEditorCore} this
13661 * @param {String} html
13665 * @event beforepush
13666 * Fires before the iframe editor is updated with content from the textarea. Return false
13667 * to cancel the push.
13668 * @param {Roo.HtmlEditorCore} this
13669 * @param {String} html
13674 * Fires when the textarea is updated with content from the editor iframe.
13675 * @param {Roo.HtmlEditorCore} this
13676 * @param {String} html
13681 * Fires when the iframe editor is updated with content from the textarea.
13682 * @param {Roo.HtmlEditorCore} this
13683 * @param {String} html
13688 * @event editorevent
13689 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13690 * @param {Roo.HtmlEditorCore} this
13698 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13702 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13708 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13713 * @cfg {Number} height (in pixels)
13717 * @cfg {Number} width (in pixels)
13722 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13725 stylesheets: false,
13730 // private properties
13731 validationEvent : false,
13733 initialized : false,
13735 sourceEditMode : false,
13736 onFocus : Roo.emptyFn,
13738 hideMode:'offsets',
13746 * Protected method that will not generally be called directly. It
13747 * is called when the editor initializes the iframe with HTML contents. Override this method if you
13748 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
13750 getDocMarkup : function(){
13753 Roo.log(this.stylesheets);
13755 // inherit styels from page...??
13756 if (this.stylesheets === false) {
13758 Roo.get(document.head).select('style').each(function(node) {
13759 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13762 Roo.get(document.head).select('link').each(function(node) {
13763 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13766 } else if (!this.stylesheets.length) {
13768 st = '<style type="text/css">' +
13769 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13772 Roo.each(this.stylesheets, function(s) {
13773 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
13778 st += '<style type="text/css">' +
13779 'IMG { cursor: pointer } ' +
13783 return '<html><head>' + st +
13784 //<style type="text/css">' +
13785 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13787 ' </head><body class="roo-htmleditor-body"></body></html>';
13791 onRender : function(ct, position)
13794 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13795 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13798 this.el.dom.style.border = '0 none';
13799 this.el.dom.setAttribute('tabIndex', -1);
13800 this.el.addClass('x-hidden hide');
13804 if(Roo.isIE){ // fix IE 1px bogus margin
13805 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13809 this.frameId = Roo.id();
13813 var iframe = this.owner.wrap.createChild({
13815 cls: 'form-control', // bootstrap..
13817 name: this.frameId,
13818 frameBorder : 'no',
13819 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
13824 this.iframe = iframe.dom;
13826 this.assignDocWin();
13828 this.doc.designMode = 'on';
13831 this.doc.write(this.getDocMarkup());
13835 var task = { // must defer to wait for browser to be ready
13837 //console.log("run task?" + this.doc.readyState);
13838 this.assignDocWin();
13839 if(this.doc.body || this.doc.readyState == 'complete'){
13841 this.doc.designMode="on";
13845 Roo.TaskMgr.stop(task);
13846 this.initEditor.defer(10, this);
13853 Roo.TaskMgr.start(task);
13860 onResize : function(w, h)
13862 Roo.log('resize: ' +w + ',' + h );
13863 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13867 if(typeof w == 'number'){
13869 this.iframe.style.width = w + 'px';
13871 if(typeof h == 'number'){
13873 this.iframe.style.height = h + 'px';
13875 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13882 * Toggles the editor between standard and source edit mode.
13883 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13885 toggleSourceEdit : function(sourceEditMode){
13887 this.sourceEditMode = sourceEditMode === true;
13889 if(this.sourceEditMode){
13891 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13894 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13895 //this.iframe.className = '';
13898 //this.setSize(this.owner.wrap.getSize());
13899 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13906 * Protected method that will not generally be called directly. If you need/want
13907 * custom HTML cleanup, this is the method you should override.
13908 * @param {String} html The HTML to be cleaned
13909 * return {String} The cleaned HTML
13911 cleanHtml : function(html){
13912 html = String(html);
13913 if(html.length > 5){
13914 if(Roo.isSafari){ // strip safari nonsense
13915 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13918 if(html == ' '){
13925 * HTML Editor -> Textarea
13926 * Protected method that will not generally be called directly. Syncs the contents
13927 * of the editor iframe with the textarea.
13929 syncValue : function(){
13930 if(this.initialized){
13931 var bd = (this.doc.body || this.doc.documentElement);
13932 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13933 var html = bd.innerHTML;
13935 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13936 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13938 html = '<div style="'+m[0]+'">' + html + '</div>';
13941 html = this.cleanHtml(html);
13942 // fix up the special chars.. normaly like back quotes in word...
13943 // however we do not want to do this with chinese..
13944 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13945 var cc = b.charCodeAt();
13947 (cc >= 0x4E00 && cc < 0xA000 ) ||
13948 (cc >= 0x3400 && cc < 0x4E00 ) ||
13949 (cc >= 0xf900 && cc < 0xfb00 )
13955 if(this.owner.fireEvent('beforesync', this, html) !== false){
13956 this.el.dom.value = html;
13957 this.owner.fireEvent('sync', this, html);
13963 * Protected method that will not generally be called directly. Pushes the value of the textarea
13964 * into the iframe editor.
13966 pushValue : function(){
13967 if(this.initialized){
13968 var v = this.el.dom.value.trim();
13970 // if(v.length < 1){
13974 if(this.owner.fireEvent('beforepush', this, v) !== false){
13975 var d = (this.doc.body || this.doc.documentElement);
13977 this.cleanUpPaste();
13978 this.el.dom.value = d.innerHTML;
13979 this.owner.fireEvent('push', this, v);
13985 deferFocus : function(){
13986 this.focus.defer(10, this);
13990 focus : function(){
13991 if(this.win && !this.sourceEditMode){
13998 assignDocWin: function()
14000 var iframe = this.iframe;
14003 this.doc = iframe.contentWindow.document;
14004 this.win = iframe.contentWindow;
14006 if (!Roo.get(this.frameId)) {
14009 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14010 this.win = Roo.get(this.frameId).dom.contentWindow;
14015 initEditor : function(){
14016 //console.log("INIT EDITOR");
14017 this.assignDocWin();
14021 this.doc.designMode="on";
14023 this.doc.write(this.getDocMarkup());
14026 var dbody = (this.doc.body || this.doc.documentElement);
14027 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14028 // this copies styles from the containing element into thsi one..
14029 // not sure why we need all of this..
14030 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14031 ss['background-attachment'] = 'fixed'; // w3c
14032 dbody.bgProperties = 'fixed'; // ie
14033 Roo.DomHelper.applyStyles(dbody, ss);
14034 Roo.EventManager.on(this.doc, {
14035 //'mousedown': this.onEditorEvent,
14036 'mouseup': this.onEditorEvent,
14037 'dblclick': this.onEditorEvent,
14038 'click': this.onEditorEvent,
14039 'keyup': this.onEditorEvent,
14044 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14046 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14047 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14049 this.initialized = true;
14051 this.owner.fireEvent('initialize', this);
14056 onDestroy : function(){
14062 //for (var i =0; i < this.toolbars.length;i++) {
14063 // // fixme - ask toolbars for heights?
14064 // this.toolbars[i].onDestroy();
14067 //this.wrap.dom.innerHTML = '';
14068 //this.wrap.remove();
14073 onFirstFocus : function(){
14075 this.assignDocWin();
14078 this.activated = true;
14081 if(Roo.isGecko){ // prevent silly gecko errors
14083 var s = this.win.getSelection();
14084 if(!s.focusNode || s.focusNode.nodeType != 3){
14085 var r = s.getRangeAt(0);
14086 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14091 this.execCmd('useCSS', true);
14092 this.execCmd('styleWithCSS', false);
14095 this.owner.fireEvent('activate', this);
14099 adjustFont: function(btn){
14100 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14101 //if(Roo.isSafari){ // safari
14104 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14105 if(Roo.isSafari){ // safari
14106 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14107 v = (v < 10) ? 10 : v;
14108 v = (v > 48) ? 48 : v;
14109 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14114 v = Math.max(1, v+adjust);
14116 this.execCmd('FontSize', v );
14119 onEditorEvent : function(e){
14120 this.owner.fireEvent('editorevent', this, e);
14121 // this.updateToolbar();
14122 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14125 insertTag : function(tg)
14127 // could be a bit smarter... -> wrap the current selected tRoo..
14128 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14130 range = this.createRange(this.getSelection());
14131 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14132 wrappingNode.appendChild(range.extractContents());
14133 range.insertNode(wrappingNode);
14140 this.execCmd("formatblock", tg);
14144 insertText : function(txt)
14148 var range = this.createRange();
14149 range.deleteContents();
14150 //alert(Sender.getAttribute('label'));
14152 range.insertNode(this.doc.createTextNode(txt));
14158 * Executes a Midas editor command on the editor document and performs necessary focus and
14159 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14160 * @param {String} cmd The Midas command
14161 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14163 relayCmd : function(cmd, value){
14165 this.execCmd(cmd, value);
14166 this.owner.fireEvent('editorevent', this);
14167 //this.updateToolbar();
14168 this.owner.deferFocus();
14172 * Executes a Midas editor command directly on the editor document.
14173 * For visual commands, you should use {@link #relayCmd} instead.
14174 * <b>This should only be called after the editor is initialized.</b>
14175 * @param {String} cmd The Midas command
14176 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14178 execCmd : function(cmd, value){
14179 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14186 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14188 * @param {String} text | dom node..
14190 insertAtCursor : function(text)
14195 if(!this.activated){
14201 var r = this.doc.selection.createRange();
14212 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14216 // from jquery ui (MIT licenced)
14218 var win = this.win;
14220 if (win.getSelection && win.getSelection().getRangeAt) {
14221 range = win.getSelection().getRangeAt(0);
14222 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14223 range.insertNode(node);
14224 } else if (win.document.selection && win.document.selection.createRange) {
14225 // no firefox support
14226 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14227 win.document.selection.createRange().pasteHTML(txt);
14229 // no firefox support
14230 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14231 this.execCmd('InsertHTML', txt);
14240 mozKeyPress : function(e){
14242 var c = e.getCharCode(), cmd;
14245 c = String.fromCharCode(c).toLowerCase();
14259 this.cleanUpPaste.defer(100, this);
14267 e.preventDefault();
14275 fixKeys : function(){ // load time branching for fastest keydown performance
14277 return function(e){
14278 var k = e.getKey(), r;
14281 r = this.doc.selection.createRange();
14284 r.pasteHTML('    ');
14291 r = this.doc.selection.createRange();
14293 var target = r.parentElement();
14294 if(!target || target.tagName.toLowerCase() != 'li'){
14296 r.pasteHTML('<br />');
14302 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14303 this.cleanUpPaste.defer(100, this);
14309 }else if(Roo.isOpera){
14310 return function(e){
14311 var k = e.getKey();
14315 this.execCmd('InsertHTML','    ');
14318 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14319 this.cleanUpPaste.defer(100, this);
14324 }else if(Roo.isSafari){
14325 return function(e){
14326 var k = e.getKey();
14330 this.execCmd('InsertText','\t');
14334 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14335 this.cleanUpPaste.defer(100, this);
14343 getAllAncestors: function()
14345 var p = this.getSelectedNode();
14348 a.push(p); // push blank onto stack..
14349 p = this.getParentElement();
14353 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14357 a.push(this.doc.body);
14361 lastSelNode : false,
14364 getSelection : function()
14366 this.assignDocWin();
14367 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14370 getSelectedNode: function()
14372 // this may only work on Gecko!!!
14374 // should we cache this!!!!
14379 var range = this.createRange(this.getSelection()).cloneRange();
14382 var parent = range.parentElement();
14384 var testRange = range.duplicate();
14385 testRange.moveToElementText(parent);
14386 if (testRange.inRange(range)) {
14389 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14392 parent = parent.parentElement;
14397 // is ancestor a text element.
14398 var ac = range.commonAncestorContainer;
14399 if (ac.nodeType == 3) {
14400 ac = ac.parentNode;
14403 var ar = ac.childNodes;
14406 var other_nodes = [];
14407 var has_other_nodes = false;
14408 for (var i=0;i<ar.length;i++) {
14409 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14412 // fullly contained node.
14414 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
14419 // probably selected..
14420 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
14421 other_nodes.push(ar[i]);
14425 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
14430 has_other_nodes = true;
14432 if (!nodes.length && other_nodes.length) {
14433 nodes= other_nodes;
14435 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
14441 createRange: function(sel)
14443 // this has strange effects when using with
14444 // top toolbar - not sure if it's a great idea.
14445 //this.editor.contentWindow.focus();
14446 if (typeof sel != "undefined") {
14448 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
14450 return this.doc.createRange();
14453 return this.doc.createRange();
14456 getParentElement: function()
14459 this.assignDocWin();
14460 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
14462 var range = this.createRange(sel);
14465 var p = range.commonAncestorContainer;
14466 while (p.nodeType == 3) { // text node
14477 * Range intersection.. the hard stuff...
14481 * [ -- selected range --- ]
14485 * if end is before start or hits it. fail.
14486 * if start is after end or hits it fail.
14488 * if either hits (but other is outside. - then it's not
14494 // @see http://www.thismuchiknow.co.uk/?p=64.
14495 rangeIntersectsNode : function(range, node)
14497 var nodeRange = node.ownerDocument.createRange();
14499 nodeRange.selectNode(node);
14501 nodeRange.selectNodeContents(node);
14504 var rangeStartRange = range.cloneRange();
14505 rangeStartRange.collapse(true);
14507 var rangeEndRange = range.cloneRange();
14508 rangeEndRange.collapse(false);
14510 var nodeStartRange = nodeRange.cloneRange();
14511 nodeStartRange.collapse(true);
14513 var nodeEndRange = nodeRange.cloneRange();
14514 nodeEndRange.collapse(false);
14516 return rangeStartRange.compareBoundaryPoints(
14517 Range.START_TO_START, nodeEndRange) == -1 &&
14518 rangeEndRange.compareBoundaryPoints(
14519 Range.START_TO_START, nodeStartRange) == 1;
14523 rangeCompareNode : function(range, node)
14525 var nodeRange = node.ownerDocument.createRange();
14527 nodeRange.selectNode(node);
14529 nodeRange.selectNodeContents(node);
14533 range.collapse(true);
14535 nodeRange.collapse(true);
14537 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
14538 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
14540 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
14542 var nodeIsBefore = ss == 1;
14543 var nodeIsAfter = ee == -1;
14545 if (nodeIsBefore && nodeIsAfter)
14547 if (!nodeIsBefore && nodeIsAfter)
14548 return 1; //right trailed.
14550 if (nodeIsBefore && !nodeIsAfter)
14551 return 2; // left trailed.
14556 // private? - in a new class?
14557 cleanUpPaste : function()
14559 // cleans up the whole document..
14560 Roo.log('cleanuppaste');
14562 this.cleanUpChildren(this.doc.body);
14563 var clean = this.cleanWordChars(this.doc.body.innerHTML);
14564 if (clean != this.doc.body.innerHTML) {
14565 this.doc.body.innerHTML = clean;
14570 cleanWordChars : function(input) {// change the chars to hex code
14571 var he = Roo.HtmlEditorCore;
14573 var output = input;
14574 Roo.each(he.swapCodes, function(sw) {
14575 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
14577 output = output.replace(swapper, sw[1]);
14584 cleanUpChildren : function (n)
14586 if (!n.childNodes.length) {
14589 for (var i = n.childNodes.length-1; i > -1 ; i--) {
14590 this.cleanUpChild(n.childNodes[i]);
14597 cleanUpChild : function (node)
14600 //console.log(node);
14601 if (node.nodeName == "#text") {
14602 // clean up silly Windows -- stuff?
14605 if (node.nodeName == "#comment") {
14606 node.parentNode.removeChild(node);
14607 // clean up silly Windows -- stuff?
14611 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
14613 node.parentNode.removeChild(node);
14618 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
14620 // remove <a name=....> as rendering on yahoo mailer is borked with this.
14621 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14623 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14624 // remove_keep_children = true;
14627 if (remove_keep_children) {
14628 this.cleanUpChildren(node);
14629 // inserts everything just before this node...
14630 while (node.childNodes.length) {
14631 var cn = node.childNodes[0];
14632 node.removeChild(cn);
14633 node.parentNode.insertBefore(cn, node);
14635 node.parentNode.removeChild(node);
14639 if (!node.attributes || !node.attributes.length) {
14640 this.cleanUpChildren(node);
14644 function cleanAttr(n,v)
14647 if (v.match(/^\./) || v.match(/^\//)) {
14650 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14653 if (v.match(/^#/)) {
14656 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14657 node.removeAttribute(n);
14661 function cleanStyle(n,v)
14663 if (v.match(/expression/)) { //XSS?? should we even bother..
14664 node.removeAttribute(n);
14667 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14668 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14671 var parts = v.split(/;/);
14674 Roo.each(parts, function(p) {
14675 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14679 var l = p.split(':').shift().replace(/\s+/g,'');
14680 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14682 if ( cblack.indexOf(l) > -1) {
14683 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14684 //node.removeAttribute(n);
14688 // only allow 'c whitelisted system attributes'
14689 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14690 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14691 //node.removeAttribute(n);
14701 if (clean.length) {
14702 node.setAttribute(n, clean.join(';'));
14704 node.removeAttribute(n);
14710 for (var i = node.attributes.length-1; i > -1 ; i--) {
14711 var a = node.attributes[i];
14714 if (a.name.toLowerCase().substr(0,2)=='on') {
14715 node.removeAttribute(a.name);
14718 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14719 node.removeAttribute(a.name);
14722 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14723 cleanAttr(a.name,a.value); // fixme..
14726 if (a.name == 'style') {
14727 cleanStyle(a.name,a.value);
14730 /// clean up MS crap..
14731 // tecnically this should be a list of valid class'es..
14734 if (a.name == 'class') {
14735 if (a.value.match(/^Mso/)) {
14736 node.className = '';
14739 if (a.value.match(/body/)) {
14740 node.className = '';
14751 this.cleanUpChildren(node);
14757 // hide stuff that is not compatible
14771 * @event specialkey
14775 * @cfg {String} fieldClass @hide
14778 * @cfg {String} focusClass @hide
14781 * @cfg {String} autoCreate @hide
14784 * @cfg {String} inputType @hide
14787 * @cfg {String} invalidClass @hide
14790 * @cfg {String} invalidText @hide
14793 * @cfg {String} msgFx @hide
14796 * @cfg {String} validateOnBlur @hide
14800 Roo.HtmlEditorCore.white = [
14801 'area', 'br', 'img', 'input', 'hr', 'wbr',
14803 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14804 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14805 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14806 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14807 'table', 'ul', 'xmp',
14809 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14812 'dir', 'menu', 'ol', 'ul', 'dl',
14818 Roo.HtmlEditorCore.black = [
14819 // 'embed', 'object', // enable - backend responsiblity to clean thiese
14821 'base', 'basefont', 'bgsound', 'blink', 'body',
14822 'frame', 'frameset', 'head', 'html', 'ilayer',
14823 'iframe', 'layer', 'link', 'meta', 'object',
14824 'script', 'style' ,'title', 'xml' // clean later..
14826 Roo.HtmlEditorCore.clean = [
14827 'script', 'style', 'title', 'xml'
14829 Roo.HtmlEditorCore.remove = [
14834 Roo.HtmlEditorCore.ablack = [
14838 Roo.HtmlEditorCore.aclean = [
14839 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14843 Roo.HtmlEditorCore.pwhite= [
14844 'http', 'https', 'mailto'
14847 // white listed style attributes.
14848 Roo.HtmlEditorCore.cwhite= [
14849 // 'text-align', /// default is to allow most things..
14855 // black listed style attributes.
14856 Roo.HtmlEditorCore.cblack= [
14857 // 'font-size' -- this can be set by the project
14861 Roo.HtmlEditorCore.swapCodes =[
14880 * @class Roo.bootstrap.HtmlEditor
14881 * @extends Roo.bootstrap.TextArea
14882 * Bootstrap HtmlEditor class
14885 * Create a new HtmlEditor
14886 * @param {Object} config The config object
14889 Roo.bootstrap.HtmlEditor = function(config){
14890 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14891 if (!this.toolbars) {
14892 this.toolbars = [];
14894 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14897 * @event initialize
14898 * Fires when the editor is fully initialized (including the iframe)
14899 * @param {HtmlEditor} this
14904 * Fires when the editor is first receives the focus. Any insertion must wait
14905 * until after this event.
14906 * @param {HtmlEditor} this
14910 * @event beforesync
14911 * Fires before the textarea is updated with content from the editor iframe. Return false
14912 * to cancel the sync.
14913 * @param {HtmlEditor} this
14914 * @param {String} html
14918 * @event beforepush
14919 * Fires before the iframe editor is updated with content from the textarea. Return false
14920 * to cancel the push.
14921 * @param {HtmlEditor} this
14922 * @param {String} html
14927 * Fires when the textarea is updated with content from the editor iframe.
14928 * @param {HtmlEditor} this
14929 * @param {String} html
14934 * Fires when the iframe editor is updated with content from the textarea.
14935 * @param {HtmlEditor} this
14936 * @param {String} html
14940 * @event editmodechange
14941 * Fires when the editor switches edit modes
14942 * @param {HtmlEditor} this
14943 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14945 editmodechange: true,
14947 * @event editorevent
14948 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14949 * @param {HtmlEditor} this
14953 * @event firstfocus
14954 * Fires when on first focus - needed by toolbars..
14955 * @param {HtmlEditor} this
14960 * Auto save the htmlEditor value as a file into Events
14961 * @param {HtmlEditor} this
14965 * @event savedpreview
14966 * preview the saved version of htmlEditor
14967 * @param {HtmlEditor} this
14974 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14978 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14983 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14988 * @cfg {Number} height (in pixels)
14992 * @cfg {Number} width (in pixels)
14997 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15000 stylesheets: false,
15005 // private properties
15006 validationEvent : false,
15008 initialized : false,
15011 onFocus : Roo.emptyFn,
15013 hideMode:'offsets',
15016 tbContainer : false,
15018 toolbarContainer :function() {
15019 return this.wrap.select('.x-html-editor-tb',true).first();
15023 * Protected method that will not generally be called directly. It
15024 * is called when the editor creates its toolbar. Override this method if you need to
15025 * add custom toolbar buttons.
15026 * @param {HtmlEditor} editor
15028 createToolbar : function(){
15030 Roo.log("create toolbars");
15032 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15033 this.toolbars[0].render(this.toolbarContainer());
15037 // if (!editor.toolbars || !editor.toolbars.length) {
15038 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15041 // for (var i =0 ; i < editor.toolbars.length;i++) {
15042 // editor.toolbars[i] = Roo.factory(
15043 // typeof(editor.toolbars[i]) == 'string' ?
15044 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15045 // Roo.bootstrap.HtmlEditor);
15046 // editor.toolbars[i].init(editor);
15052 onRender : function(ct, position)
15054 // Roo.log("Call onRender: " + this.xtype);
15056 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15058 this.wrap = this.inputEl().wrap({
15059 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15062 this.editorcore.onRender(ct, position);
15064 if (this.resizable) {
15065 this.resizeEl = new Roo.Resizable(this.wrap, {
15069 minHeight : this.height,
15070 height: this.height,
15071 handles : this.resizable,
15074 resize : function(r, w, h) {
15075 _t.onResize(w,h); // -something
15081 this.createToolbar(this);
15084 if(!this.width && this.resizable){
15085 this.setSize(this.wrap.getSize());
15087 if (this.resizeEl) {
15088 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15089 // should trigger onReize..
15095 onResize : function(w, h)
15097 Roo.log('resize: ' +w + ',' + h );
15098 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15102 if(this.inputEl() ){
15103 if(typeof w == 'number'){
15104 var aw = w - this.wrap.getFrameWidth('lr');
15105 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15108 if(typeof h == 'number'){
15109 var tbh = -11; // fixme it needs to tool bar size!
15110 for (var i =0; i < this.toolbars.length;i++) {
15111 // fixme - ask toolbars for heights?
15112 tbh += this.toolbars[i].el.getHeight();
15113 //if (this.toolbars[i].footer) {
15114 // tbh += this.toolbars[i].footer.el.getHeight();
15122 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15123 ah -= 5; // knock a few pixes off for look..
15124 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15128 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15129 this.editorcore.onResize(ew,eh);
15134 * Toggles the editor between standard and source edit mode.
15135 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15137 toggleSourceEdit : function(sourceEditMode)
15139 this.editorcore.toggleSourceEdit(sourceEditMode);
15141 if(this.editorcore.sourceEditMode){
15142 Roo.log('editor - showing textarea');
15145 // Roo.log(this.syncValue());
15147 this.inputEl().removeClass('hide');
15148 this.inputEl().dom.removeAttribute('tabIndex');
15149 this.inputEl().focus();
15151 Roo.log('editor - hiding textarea');
15153 // Roo.log(this.pushValue());
15156 this.inputEl().addClass('hide');
15157 this.inputEl().dom.setAttribute('tabIndex', -1);
15158 //this.deferFocus();
15161 if(this.resizable){
15162 this.setSize(this.wrap.getSize());
15165 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15168 // private (for BoxComponent)
15169 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15171 // private (for BoxComponent)
15172 getResizeEl : function(){
15176 // private (for BoxComponent)
15177 getPositionEl : function(){
15182 initEvents : function(){
15183 this.originalValue = this.getValue();
15187 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15190 // markInvalid : Roo.emptyFn,
15192 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15195 // clearInvalid : Roo.emptyFn,
15197 setValue : function(v){
15198 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15199 this.editorcore.pushValue();
15204 deferFocus : function(){
15205 this.focus.defer(10, this);
15209 focus : function(){
15210 this.editorcore.focus();
15216 onDestroy : function(){
15222 for (var i =0; i < this.toolbars.length;i++) {
15223 // fixme - ask toolbars for heights?
15224 this.toolbars[i].onDestroy();
15227 this.wrap.dom.innerHTML = '';
15228 this.wrap.remove();
15233 onFirstFocus : function(){
15234 //Roo.log("onFirstFocus");
15235 this.editorcore.onFirstFocus();
15236 for (var i =0; i < this.toolbars.length;i++) {
15237 this.toolbars[i].onFirstFocus();
15243 syncValue : function()
15245 this.editorcore.syncValue();
15248 pushValue : function()
15250 this.editorcore.pushValue();
15254 // hide stuff that is not compatible
15268 * @event specialkey
15272 * @cfg {String} fieldClass @hide
15275 * @cfg {String} focusClass @hide
15278 * @cfg {String} autoCreate @hide
15281 * @cfg {String} inputType @hide
15284 * @cfg {String} invalidClass @hide
15287 * @cfg {String} invalidText @hide
15290 * @cfg {String} msgFx @hide
15293 * @cfg {String} validateOnBlur @hide
15304 * @class Roo.bootstrap.HtmlEditorToolbar1
15309 new Roo.bootstrap.HtmlEditor({
15312 new Roo.bootstrap.HtmlEditorToolbar1({
15313 disable : { fonts: 1 , format: 1, ..., ... , ...],
15319 * @cfg {Object} disable List of elements to disable..
15320 * @cfg {Array} btns List of additional buttons.
15324 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
15327 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
15330 Roo.apply(this, config);
15332 // default disabled, based on 'good practice'..
15333 this.disable = this.disable || {};
15334 Roo.applyIf(this.disable, {
15337 specialElements : true
15339 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
15341 this.editor = config.editor;
15342 this.editorcore = config.editor.editorcore;
15344 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
15346 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
15347 // dont call parent... till later.
15349 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
15355 editorcore : false,
15360 "h1","h2","h3","h4","h5","h6",
15362 "abbr", "acronym", "address", "cite", "samp", "var",
15366 onRender : function(ct, position)
15368 // Roo.log("Call onRender: " + this.xtype);
15370 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
15372 this.el.dom.style.marginBottom = '0';
15374 var editorcore = this.editorcore;
15375 var editor= this.editor;
15378 var btn = function(id,cmd , toggle, handler){
15380 var event = toggle ? 'toggle' : 'click';
15385 xns: Roo.bootstrap,
15388 enableToggle:toggle !== false,
15390 pressed : toggle ? false : null,
15393 a.listeners[toggle ? 'toggle' : 'click'] = function() {
15394 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
15403 xns: Roo.bootstrap,
15404 glyphicon : 'font',
15408 xns: Roo.bootstrap,
15412 Roo.each(this.formats, function(f) {
15413 style.menu.items.push({
15415 xns: Roo.bootstrap,
15416 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
15421 editorcore.insertTag(this.tagname);
15428 children.push(style);
15431 btn('bold',false,true);
15432 btn('italic',false,true);
15433 btn('align-left', 'justifyleft',true);
15434 btn('align-center', 'justifycenter',true);
15435 btn('align-right' , 'justifyright',true);
15436 btn('link', false, false, function(btn) {
15437 //Roo.log("create link?");
15438 var url = prompt(this.createLinkText, this.defaultLinkValue);
15439 if(url && url != 'http:/'+'/'){
15440 this.editorcore.relayCmd('createlink', url);
15443 btn('list','insertunorderedlist',true);
15444 btn('pencil', false,true, function(btn){
15447 this.toggleSourceEdit(btn.pressed);
15453 xns: Roo.bootstrap,
15458 xns: Roo.bootstrap,
15463 cog.menu.items.push({
15465 xns: Roo.bootstrap,
15466 html : Clean styles,
15471 editorcore.insertTag(this.tagname);
15480 this.xtype = 'Navbar';
15482 for(var i=0;i< children.length;i++) {
15484 this.buttons.add(this.addxtypeChild(children[i]));
15488 editor.on('editorevent', this.updateToolbar, this);
15490 onBtnClick : function(id)
15492 this.editorcore.relayCmd(id);
15493 this.editorcore.focus();
15497 * Protected method that will not generally be called directly. It triggers
15498 * a toolbar update by reading the markup state of the current selection in the editor.
15500 updateToolbar: function(){
15502 if(!this.editorcore.activated){
15503 this.editor.onFirstFocus(); // is this neeed?
15507 var btns = this.buttons;
15508 var doc = this.editorcore.doc;
15509 btns.get('bold').setActive(doc.queryCommandState('bold'));
15510 btns.get('italic').setActive(doc.queryCommandState('italic'));
15511 //btns.get('underline').setActive(doc.queryCommandState('underline'));
15513 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
15514 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
15515 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
15517 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
15518 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
15521 var ans = this.editorcore.getAllAncestors();
15522 if (this.formatCombo) {
15525 var store = this.formatCombo.store;
15526 this.formatCombo.setValue("");
15527 for (var i =0; i < ans.length;i++) {
15528 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
15530 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
15538 // hides menus... - so this cant be on a menu...
15539 Roo.bootstrap.MenuMgr.hideAll();
15541 Roo.bootstrap.MenuMgr.hideAll();
15542 //this.editorsyncValue();
15544 onFirstFocus: function() {
15545 this.buttons.each(function(item){
15549 toggleSourceEdit : function(sourceEditMode){
15552 if(sourceEditMode){
15553 Roo.log("disabling buttons");
15554 this.buttons.each( function(item){
15555 if(item.cmd != 'pencil'){
15561 Roo.log("enabling buttons");
15562 if(this.editorcore.initialized){
15563 this.buttons.each( function(item){
15569 Roo.log("calling toggole on editor");
15570 // tell the editor that it's been pressed..
15571 this.editor.toggleSourceEdit(sourceEditMode);
15581 * @class Roo.bootstrap.Table.AbstractSelectionModel
15582 * @extends Roo.util.Observable
15583 * Abstract base class for grid SelectionModels. It provides the interface that should be
15584 * implemented by descendant classes. This class should not be directly instantiated.
15587 Roo.bootstrap.Table.AbstractSelectionModel = function(){
15588 this.locked = false;
15589 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
15593 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
15594 /** @ignore Called by the grid automatically. Do not call directly. */
15595 init : function(grid){
15601 * Locks the selections.
15604 this.locked = true;
15608 * Unlocks the selections.
15610 unlock : function(){
15611 this.locked = false;
15615 * Returns true if the selections are locked.
15616 * @return {Boolean}
15618 isLocked : function(){
15619 return this.locked;
15623 * @class Roo.bootstrap.Table.ColumnModel
15624 * @extends Roo.util.Observable
15625 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15626 * the columns in the table.
15629 * @param {Object} config An Array of column config objects. See this class's
15630 * config objects for details.
15632 Roo.bootstrap.Table.ColumnModel = function(config){
15634 * The config passed into the constructor
15636 this.config = config;
15639 // if no id, create one
15640 // if the column does not have a dataIndex mapping,
15641 // map it to the order it is in the config
15642 for(var i = 0, len = config.length; i < len; i++){
15644 if(typeof c.dataIndex == "undefined"){
15647 if(typeof c.renderer == "string"){
15648 c.renderer = Roo.util.Format[c.renderer];
15650 if(typeof c.id == "undefined"){
15653 // if(c.editor && c.editor.xtype){
15654 // c.editor = Roo.factory(c.editor, Roo.grid);
15656 // if(c.editor && c.editor.isFormField){
15657 // c.editor = new Roo.grid.GridEditor(c.editor);
15660 this.lookup[c.id] = c;
15664 * The width of columns which have no width specified (defaults to 100)
15667 this.defaultWidth = 100;
15670 * Default sortable of columns which have no sortable specified (defaults to false)
15673 this.defaultSortable = false;
15677 * @event widthchange
15678 * Fires when the width of a column changes.
15679 * @param {ColumnModel} this
15680 * @param {Number} columnIndex The column index
15681 * @param {Number} newWidth The new width
15683 "widthchange": true,
15685 * @event headerchange
15686 * Fires when the text of a header changes.
15687 * @param {ColumnModel} this
15688 * @param {Number} columnIndex The column index
15689 * @param {Number} newText The new header text
15691 "headerchange": true,
15693 * @event hiddenchange
15694 * Fires when a column is hidden or "unhidden".
15695 * @param {ColumnModel} this
15696 * @param {Number} columnIndex The column index
15697 * @param {Boolean} hidden true if hidden, false otherwise
15699 "hiddenchange": true,
15701 * @event columnmoved
15702 * Fires when a column is moved.
15703 * @param {ColumnModel} this
15704 * @param {Number} oldIndex
15705 * @param {Number} newIndex
15707 "columnmoved" : true,
15709 * @event columlockchange
15710 * Fires when a column's locked state is changed
15711 * @param {ColumnModel} this
15712 * @param {Number} colIndex
15713 * @param {Boolean} locked true if locked
15715 "columnlockchange" : true
15717 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15719 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15721 * @cfg {String} header The header text to display in the Grid view.
15724 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15725 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15726 * specified, the column's index is used as an index into the Record's data Array.
15729 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15730 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15733 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15734 * Defaults to the value of the {@link #defaultSortable} property.
15735 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
15738 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
15741 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
15744 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
15747 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
15750 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
15751 * given the cell's data value. See {@link #setRenderer}. If not specified, the
15752 * default renderer uses the raw data value.
15755 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
15759 * Returns the id of the column at the specified index.
15760 * @param {Number} index The column index
15761 * @return {String} the id
15763 getColumnId : function(index){
15764 return this.config[index].id;
15768 * Returns the column for a specified id.
15769 * @param {String} id The column id
15770 * @return {Object} the column
15772 getColumnById : function(id){
15773 return this.lookup[id];
15778 * Returns the column for a specified dataIndex.
15779 * @param {String} dataIndex The column dataIndex
15780 * @return {Object|Boolean} the column or false if not found
15782 getColumnByDataIndex: function(dataIndex){
15783 var index = this.findColumnIndex(dataIndex);
15784 return index > -1 ? this.config[index] : false;
15788 * Returns the index for a specified column id.
15789 * @param {String} id The column id
15790 * @return {Number} the index, or -1 if not found
15792 getIndexById : function(id){
15793 for(var i = 0, len = this.config.length; i < len; i++){
15794 if(this.config[i].id == id){
15802 * Returns the index for a specified column dataIndex.
15803 * @param {String} dataIndex The column dataIndex
15804 * @return {Number} the index, or -1 if not found
15807 findColumnIndex : function(dataIndex){
15808 for(var i = 0, len = this.config.length; i < len; i++){
15809 if(this.config[i].dataIndex == dataIndex){
15817 moveColumn : function(oldIndex, newIndex){
15818 var c = this.config[oldIndex];
15819 this.config.splice(oldIndex, 1);
15820 this.config.splice(newIndex, 0, c);
15821 this.dataMap = null;
15822 this.fireEvent("columnmoved", this, oldIndex, newIndex);
15825 isLocked : function(colIndex){
15826 return this.config[colIndex].locked === true;
15829 setLocked : function(colIndex, value, suppressEvent){
15830 if(this.isLocked(colIndex) == value){
15833 this.config[colIndex].locked = value;
15834 if(!suppressEvent){
15835 this.fireEvent("columnlockchange", this, colIndex, value);
15839 getTotalLockedWidth : function(){
15840 var totalWidth = 0;
15841 for(var i = 0; i < this.config.length; i++){
15842 if(this.isLocked(i) && !this.isHidden(i)){
15843 this.totalWidth += this.getColumnWidth(i);
15849 getLockedCount : function(){
15850 for(var i = 0, len = this.config.length; i < len; i++){
15851 if(!this.isLocked(i)){
15858 * Returns the number of columns.
15861 getColumnCount : function(visibleOnly){
15862 if(visibleOnly === true){
15864 for(var i = 0, len = this.config.length; i < len; i++){
15865 if(!this.isHidden(i)){
15871 return this.config.length;
15875 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15876 * @param {Function} fn
15877 * @param {Object} scope (optional)
15878 * @return {Array} result
15880 getColumnsBy : function(fn, scope){
15882 for(var i = 0, len = this.config.length; i < len; i++){
15883 var c = this.config[i];
15884 if(fn.call(scope||this, c, i) === true){
15892 * Returns true if the specified column is sortable.
15893 * @param {Number} col The column index
15894 * @return {Boolean}
15896 isSortable : function(col){
15897 if(typeof this.config[col].sortable == "undefined"){
15898 return this.defaultSortable;
15900 return this.config[col].sortable;
15904 * Returns the rendering (formatting) function defined for the column.
15905 * @param {Number} col The column index.
15906 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15908 getRenderer : function(col){
15909 if(!this.config[col].renderer){
15910 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15912 return this.config[col].renderer;
15916 * Sets the rendering (formatting) function for a column.
15917 * @param {Number} col The column index
15918 * @param {Function} fn The function to use to process the cell's raw data
15919 * to return HTML markup for the grid view. The render function is called with
15920 * the following parameters:<ul>
15921 * <li>Data value.</li>
15922 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15923 * <li>css A CSS style string to apply to the table cell.</li>
15924 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15925 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15926 * <li>Row index</li>
15927 * <li>Column index</li>
15928 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15930 setRenderer : function(col, fn){
15931 this.config[col].renderer = fn;
15935 * Returns the width for the specified column.
15936 * @param {Number} col The column index
15939 getColumnWidth : function(col){
15940 return this.config[col].width * 1 || this.defaultWidth;
15944 * Sets the width for a column.
15945 * @param {Number} col The column index
15946 * @param {Number} width The new width
15948 setColumnWidth : function(col, width, suppressEvent){
15949 this.config[col].width = width;
15950 this.totalWidth = null;
15951 if(!suppressEvent){
15952 this.fireEvent("widthchange", this, col, width);
15957 * Returns the total width of all columns.
15958 * @param {Boolean} includeHidden True to include hidden column widths
15961 getTotalWidth : function(includeHidden){
15962 if(!this.totalWidth){
15963 this.totalWidth = 0;
15964 for(var i = 0, len = this.config.length; i < len; i++){
15965 if(includeHidden || !this.isHidden(i)){
15966 this.totalWidth += this.getColumnWidth(i);
15970 return this.totalWidth;
15974 * Returns the header for the specified column.
15975 * @param {Number} col The column index
15978 getColumnHeader : function(col){
15979 return this.config[col].header;
15983 * Sets the header for a column.
15984 * @param {Number} col The column index
15985 * @param {String} header The new header
15987 setColumnHeader : function(col, header){
15988 this.config[col].header = header;
15989 this.fireEvent("headerchange", this, col, header);
15993 * Returns the tooltip for the specified column.
15994 * @param {Number} col The column index
15997 getColumnTooltip : function(col){
15998 return this.config[col].tooltip;
16001 * Sets the tooltip for a column.
16002 * @param {Number} col The column index
16003 * @param {String} tooltip The new tooltip
16005 setColumnTooltip : function(col, tooltip){
16006 this.config[col].tooltip = tooltip;
16010 * Returns the dataIndex for the specified column.
16011 * @param {Number} col The column index
16014 getDataIndex : function(col){
16015 return this.config[col].dataIndex;
16019 * Sets the dataIndex for a column.
16020 * @param {Number} col The column index
16021 * @param {Number} dataIndex The new dataIndex
16023 setDataIndex : function(col, dataIndex){
16024 this.config[col].dataIndex = dataIndex;
16030 * Returns true if the cell is editable.
16031 * @param {Number} colIndex The column index
16032 * @param {Number} rowIndex The row index
16033 * @return {Boolean}
16035 isCellEditable : function(colIndex, rowIndex){
16036 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16040 * Returns the editor defined for the cell/column.
16041 * return false or null to disable editing.
16042 * @param {Number} colIndex The column index
16043 * @param {Number} rowIndex The row index
16046 getCellEditor : function(colIndex, rowIndex){
16047 return this.config[colIndex].editor;
16051 * Sets if a column is editable.
16052 * @param {Number} col The column index
16053 * @param {Boolean} editable True if the column is editable
16055 setEditable : function(col, editable){
16056 this.config[col].editable = editable;
16061 * Returns true if the column is hidden.
16062 * @param {Number} colIndex The column index
16063 * @return {Boolean}
16065 isHidden : function(colIndex){
16066 return this.config[colIndex].hidden;
16071 * Returns true if the column width cannot be changed
16073 isFixed : function(colIndex){
16074 return this.config[colIndex].fixed;
16078 * Returns true if the column can be resized
16079 * @return {Boolean}
16081 isResizable : function(colIndex){
16082 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16085 * Sets if a column is hidden.
16086 * @param {Number} colIndex The column index
16087 * @param {Boolean} hidden True if the column is hidden
16089 setHidden : function(colIndex, hidden){
16090 this.config[colIndex].hidden = hidden;
16091 this.totalWidth = null;
16092 this.fireEvent("hiddenchange", this, colIndex, hidden);
16096 * Sets the editor for a column.
16097 * @param {Number} col The column index
16098 * @param {Object} editor The editor object
16100 setEditor : function(col, editor){
16101 this.config[col].editor = editor;
16105 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16106 if(typeof value == "string" && value.length < 1){
16112 // Alias for backwards compatibility
16113 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16116 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16117 * @class Roo.bootstrap.Table.RowSelectionModel
16118 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16119 * It supports multiple selections and keyboard selection/navigation.
16121 * @param {Object} config
16124 Roo.bootstrap.Table.RowSelectionModel = function(config){
16125 Roo.apply(this, config);
16126 this.selections = new Roo.util.MixedCollection(false, function(o){
16131 this.lastActive = false;
16135 * @event selectionchange
16136 * Fires when the selection changes
16137 * @param {SelectionModel} this
16139 "selectionchange" : true,
16141 * @event afterselectionchange
16142 * Fires after the selection changes (eg. by key press or clicking)
16143 * @param {SelectionModel} this
16145 "afterselectionchange" : true,
16147 * @event beforerowselect
16148 * Fires when a row is selected being selected, return false to cancel.
16149 * @param {SelectionModel} this
16150 * @param {Number} rowIndex The selected index
16151 * @param {Boolean} keepExisting False if other selections will be cleared
16153 "beforerowselect" : true,
16156 * Fires when a row is selected.
16157 * @param {SelectionModel} this
16158 * @param {Number} rowIndex The selected index
16159 * @param {Roo.data.Record} r The record
16161 "rowselect" : true,
16163 * @event rowdeselect
16164 * Fires when a row is deselected.
16165 * @param {SelectionModel} this
16166 * @param {Number} rowIndex The selected index
16168 "rowdeselect" : true
16170 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16171 this.locked = false;
16174 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16176 * @cfg {Boolean} singleSelect
16177 * True to allow selection of only one row at a time (defaults to false)
16179 singleSelect : false,
16182 initEvents : function(){
16184 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16185 this.grid.on("mousedown", this.handleMouseDown, this);
16186 }else{ // allow click to work like normal
16187 this.grid.on("rowclick", this.handleDragableRowClick, this);
16190 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16191 "up" : function(e){
16193 this.selectPrevious(e.shiftKey);
16194 }else if(this.last !== false && this.lastActive !== false){
16195 var last = this.last;
16196 this.selectRange(this.last, this.lastActive-1);
16197 this.grid.getView().focusRow(this.lastActive);
16198 if(last !== false){
16202 this.selectFirstRow();
16204 this.fireEvent("afterselectionchange", this);
16206 "down" : function(e){
16208 this.selectNext(e.shiftKey);
16209 }else if(this.last !== false && this.lastActive !== false){
16210 var last = this.last;
16211 this.selectRange(this.last, this.lastActive+1);
16212 this.grid.getView().focusRow(this.lastActive);
16213 if(last !== false){
16217 this.selectFirstRow();
16219 this.fireEvent("afterselectionchange", this);
16224 var view = this.grid.view;
16225 view.on("refresh", this.onRefresh, this);
16226 view.on("rowupdated", this.onRowUpdated, this);
16227 view.on("rowremoved", this.onRemove, this);
16231 onRefresh : function(){
16232 var ds = this.grid.dataSource, i, v = this.grid.view;
16233 var s = this.selections;
16234 s.each(function(r){
16235 if((i = ds.indexOfId(r.id)) != -1){
16244 onRemove : function(v, index, r){
16245 this.selections.remove(r);
16249 onRowUpdated : function(v, index, r){
16250 if(this.isSelected(r)){
16251 v.onRowSelect(index);
16257 * @param {Array} records The records to select
16258 * @param {Boolean} keepExisting (optional) True to keep existing selections
16260 selectRecords : function(records, keepExisting){
16262 this.clearSelections();
16264 var ds = this.grid.dataSource;
16265 for(var i = 0, len = records.length; i < len; i++){
16266 this.selectRow(ds.indexOf(records[i]), true);
16271 * Gets the number of selected rows.
16274 getCount : function(){
16275 return this.selections.length;
16279 * Selects the first row in the grid.
16281 selectFirstRow : function(){
16286 * Select the last row.
16287 * @param {Boolean} keepExisting (optional) True to keep existing selections
16289 selectLastRow : function(keepExisting){
16290 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
16294 * Selects the row immediately following the last selected row.
16295 * @param {Boolean} keepExisting (optional) True to keep existing selections
16297 selectNext : function(keepExisting){
16298 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
16299 this.selectRow(this.last+1, keepExisting);
16300 this.grid.getView().focusRow(this.last);
16305 * Selects the row that precedes the last selected row.
16306 * @param {Boolean} keepExisting (optional) True to keep existing selections
16308 selectPrevious : function(keepExisting){
16310 this.selectRow(this.last-1, keepExisting);
16311 this.grid.getView().focusRow(this.last);
16316 * Returns the selected records
16317 * @return {Array} Array of selected records
16319 getSelections : function(){
16320 return [].concat(this.selections.items);
16324 * Returns the first selected record.
16327 getSelected : function(){
16328 return this.selections.itemAt(0);
16333 * Clears all selections.
16335 clearSelections : function(fast){
16336 if(this.locked) return;
16338 var ds = this.grid.dataSource;
16339 var s = this.selections;
16340 s.each(function(r){
16341 this.deselectRow(ds.indexOfId(r.id));
16345 this.selections.clear();
16352 * Selects all rows.
16354 selectAll : function(){
16355 if(this.locked) return;
16356 this.selections.clear();
16357 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
16358 this.selectRow(i, true);
16363 * Returns True if there is a selection.
16364 * @return {Boolean}
16366 hasSelection : function(){
16367 return this.selections.length > 0;
16371 * Returns True if the specified row is selected.
16372 * @param {Number/Record} record The record or index of the record to check
16373 * @return {Boolean}
16375 isSelected : function(index){
16376 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
16377 return (r && this.selections.key(r.id) ? true : false);
16381 * Returns True if the specified record id is selected.
16382 * @param {String} id The id of record to check
16383 * @return {Boolean}
16385 isIdSelected : function(id){
16386 return (this.selections.key(id) ? true : false);
16390 handleMouseDown : function(e, t){
16391 var view = this.grid.getView(), rowIndex;
16392 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
16395 if(e.shiftKey && this.last !== false){
16396 var last = this.last;
16397 this.selectRange(last, rowIndex, e.ctrlKey);
16398 this.last = last; // reset the last
16399 view.focusRow(rowIndex);
16401 var isSelected = this.isSelected(rowIndex);
16402 if(e.button !== 0 && isSelected){
16403 view.focusRow(rowIndex);
16404 }else if(e.ctrlKey && isSelected){
16405 this.deselectRow(rowIndex);
16406 }else if(!isSelected){
16407 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
16408 view.focusRow(rowIndex);
16411 this.fireEvent("afterselectionchange", this);
16414 handleDragableRowClick : function(grid, rowIndex, e)
16416 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
16417 this.selectRow(rowIndex, false);
16418 grid.view.focusRow(rowIndex);
16419 this.fireEvent("afterselectionchange", this);
16424 * Selects multiple rows.
16425 * @param {Array} rows Array of the indexes of the row to select
16426 * @param {Boolean} keepExisting (optional) True to keep existing selections
16428 selectRows : function(rows, keepExisting){
16430 this.clearSelections();
16432 for(var i = 0, len = rows.length; i < len; i++){
16433 this.selectRow(rows[i], true);
16438 * Selects a range of rows. All rows in between startRow and endRow are also selected.
16439 * @param {Number} startRow The index of the first row in the range
16440 * @param {Number} endRow The index of the last row in the range
16441 * @param {Boolean} keepExisting (optional) True to retain existing selections
16443 selectRange : function(startRow, endRow, keepExisting){
16444 if(this.locked) return;
16446 this.clearSelections();
16448 if(startRow <= endRow){
16449 for(var i = startRow; i <= endRow; i++){
16450 this.selectRow(i, true);
16453 for(var i = startRow; i >= endRow; i--){
16454 this.selectRow(i, true);
16460 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
16461 * @param {Number} startRow The index of the first row in the range
16462 * @param {Number} endRow The index of the last row in the range
16464 deselectRange : function(startRow, endRow, preventViewNotify){
16465 if(this.locked) return;
16466 for(var i = startRow; i <= endRow; i++){
16467 this.deselectRow(i, preventViewNotify);
16473 * @param {Number} row The index of the row to select
16474 * @param {Boolean} keepExisting (optional) True to keep existing selections
16476 selectRow : function(index, keepExisting, preventViewNotify){
16477 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
16478 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
16479 if(!keepExisting || this.singleSelect){
16480 this.clearSelections();
16482 var r = this.grid.dataSource.getAt(index);
16483 this.selections.add(r);
16484 this.last = this.lastActive = index;
16485 if(!preventViewNotify){
16486 this.grid.getView().onRowSelect(index);
16488 this.fireEvent("rowselect", this, index, r);
16489 this.fireEvent("selectionchange", this);
16495 * @param {Number} row The index of the row to deselect
16497 deselectRow : function(index, preventViewNotify){
16498 if(this.locked) return;
16499 if(this.last == index){
16502 if(this.lastActive == index){
16503 this.lastActive = false;
16505 var r = this.grid.dataSource.getAt(index);
16506 this.selections.remove(r);
16507 if(!preventViewNotify){
16508 this.grid.getView().onRowDeselect(index);
16510 this.fireEvent("rowdeselect", this, index);
16511 this.fireEvent("selectionchange", this);
16515 restoreLast : function(){
16517 this.last = this._last;
16522 acceptsNav : function(row, col, cm){
16523 return !cm.isHidden(col) && cm.isCellEditable(col, row);
16527 onEditorKey : function(field, e){
16528 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
16533 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
16535 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
16537 }else if(k == e.ENTER && !e.ctrlKey){
16541 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
16543 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
16545 }else if(k == e.ESC){
16549 g.startEditing(newCell[0], newCell[1]);
16560 * @class Roo.bootstrap.MessageBar
16561 * @extends Roo.bootstrap.Component
16562 * Bootstrap MessageBar class
16563 * @cfg {String} html contents of the MessageBar
16564 * @cfg {String} weight (info | success | warning | danger) default info
16565 * @cfg {String} beforeClass insert the bar before the given class
16566 * @cfg {Boolean} closable (true | false) default false
16567 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
16570 * Create a new Element
16571 * @param {Object} config The config object
16574 Roo.bootstrap.MessageBar = function(config){
16575 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
16578 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
16584 beforeClass: 'bootstrap-sticky-wrap',
16586 getAutoCreate : function(){
16590 cls: 'alert alert-dismissable alert-' + this.weight,
16595 html: this.html || ''
16601 cfg.cls += ' alert-messages-fixed';
16615 onRender : function(ct, position)
16617 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16620 var cfg = Roo.apply({}, this.getAutoCreate());
16624 cfg.cls += ' ' + this.cls;
16627 cfg.style = this.style;
16629 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16631 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16634 this.el.select('>button.close').on('click', this.hide, this);
16640 if (!this.rendered) {
16646 this.fireEvent('show', this);
16652 if (!this.rendered) {
16658 this.fireEvent('hide', this);
16661 update : function()
16663 // var e = this.el.dom.firstChild;
16665 // if(this.closable){
16666 // e = e.nextSibling;
16669 // e.data = this.html || '';
16671 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';