4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
300 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
305 onRender : function(ct, position){
308 //this.el.addClass([this.fieldClass, this.cls]);
326 * @class Roo.bootstrap.ButtonGroup
327 * @extends Roo.bootstrap.Component
328 * Bootstrap ButtonGroup class
329 * @cfg {String} size lg | sm | xs (default empty normal)
330 * @cfg {String} align vertical | justified (default none)
331 * @cfg {String} direction up | down (default down)
332 * @cfg {Boolean} toolbar false | true
333 * @cfg {Boolean} btn true | false
338 * @param {Object} config The config object
341 Roo.bootstrap.ButtonGroup = function(config){
342 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
345 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
353 getAutoCreate : function(){
359 cfg.html = this.html || cfg.html;
370 if (['vertical','justified'].indexOf(this.align)!==-1) {
371 cfg.cls = 'btn-group-' + this.align;
373 if (this.align == 'justified') {
374 console.log(this.items);
378 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
379 cfg.cls += ' btn-group-' + this.size;
382 if (this.direction == 'up') {
383 cfg.cls += ' dropup' ;
399 * @class Roo.bootstrap.Button
400 * @extends Roo.bootstrap.Component
401 * Bootstrap Button class
402 * @cfg {String} html The button content
403 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
404 * @cfg {String} size empty | lg | sm | xs
405 * @cfg {String} tag empty | a | input | submit
406 * @cfg {String} href empty or href
407 * @cfg {Boolean} disabled false | true
408 * @cfg {Boolean} isClose false | true
409 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
410 * @cfg {String} badge text for badge
411 * @cfg {String} theme default (or empty) | glow
412 * @cfg {Boolean} inverse false | true
413 * @cfg {Boolean} toggle false | true
414 * @cfg {String} ontext text for on toggle state
415 * @cfg {String} offtext text for off toggle state
416 * @cfg {Boolean} defaulton true | false
417 * @cfg {Boolean} preventDefault (true | false) default true
418 * @cfg {Boolean} removeClass true | false remove the standard class..
419 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
422 * Create a new button
423 * @param {Object} config The config object
427 Roo.bootstrap.Button = function(config){
428 Roo.bootstrap.Button.superclass.constructor.call(this, config);
433 * When a butotn is pressed
434 * @param {Roo.EventObject} e
439 * After the button has been toggles
440 * @param {Roo.EventObject} e
441 * @param {boolean} pressed (also available as button.pressed)
447 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
465 preventDefault: true,
474 getAutoCreate : function(){
482 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
483 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
488 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
490 if (this.toggle == true) {
493 cls: 'slider-frame roo-button',
498 'data-off-text':'OFF',
499 cls: 'slider-button',
505 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
506 cfg.cls += ' '+this.weight;
515 cfg["aria-hidden"] = true;
517 cfg.html = "×";
523 if (this.theme==='default') {
524 cfg.cls = 'btn roo-button';
526 //if (this.parentType != 'Navbar') {
527 this.weight = this.weight.length ? this.weight : 'default';
529 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
531 cfg.cls += ' btn-' + this.weight;
533 } else if (this.theme==='glow') {
536 cfg.cls = 'btn-glow roo-button';
538 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
540 cfg.cls += ' ' + this.weight;
546 this.cls += ' inverse';
551 cfg.cls += ' active';
555 cfg.disabled = 'disabled';
559 Roo.log('changing to ul' );
561 this.glyphicon = 'caret';
564 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
566 //gsRoo.log(this.parentType);
567 if (this.parentType === 'Navbar' && !this.parent().bar) {
568 Roo.log('changing to li?');
577 href : this.href || '#'
580 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
581 cfg.cls += ' dropdown';
588 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
590 if (this.glyphicon) {
591 cfg.html = ' ' + cfg.html;
596 cls: 'glyphicon glyphicon-' + this.glyphicon
606 // cfg.cls='btn roo-button';
610 var value = cfg.html;
615 cls: 'glyphicon glyphicon-' + this.glyphicon,
634 cfg.cls += ' dropdown';
635 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
638 if (cfg.tag !== 'a' && this.href !== '') {
639 throw "Tag must be a to set href.";
640 } else if (this.href.length > 0) {
641 cfg.href = this.href;
644 if(this.removeClass){
649 cfg.target = this.target;
654 initEvents: function() {
655 // Roo.log('init events?');
656 // Roo.log(this.el.dom);
657 if (this.el.hasClass('roo-button')) {
658 this.el.on('click', this.onClick, this);
660 this.el.select('.roo-button').on('click', this.onClick, this);
663 this.el.enableDisplayMode();
666 onClick : function(e)
672 Roo.log('button on click ');
673 if(this.preventDefault){
676 if (this.pressed === true || this.pressed === false) {
677 this.pressed = !this.pressed;
678 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
679 this.fireEvent('toggle', this, e, this.pressed);
683 this.fireEvent('click', this, e);
687 * Enables this button
691 this.disabled = false;
692 this.el.removeClass('disabled');
696 * Disable this button
700 this.disabled = true;
701 this.el.addClass('disabled');
704 * sets the active state on/off,
705 * @param {Boolean} state (optional) Force a particular state
707 setActive : function(v) {
709 this.el[v ? 'addClass' : 'removeClass']('active');
712 * toggles the current active state
714 toggleActive : function()
716 var active = this.el.hasClass('active');
717 this.setActive(!active);
721 setText : function(str)
723 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
746 * @class Roo.bootstrap.Column
747 * @extends Roo.bootstrap.Component
748 * Bootstrap Column class
749 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
750 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
751 * @cfg {Number} md colspan out of 12 for computer-sized screens
752 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
753 * @cfg {String} html content of column.
756 * Create a new Column
757 * @param {Object} config The config object
760 Roo.bootstrap.Column = function(config){
761 Roo.bootstrap.Column.superclass.constructor.call(this, config);
764 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
773 getAutoCreate : function(){
774 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
782 ['xs','sm','md','lg'].map(function(size){
783 if (settings[size]) {
784 cfg.cls += ' col-' + size + '-' + settings[size];
787 if (this.html.length) {
788 cfg.html = this.html;
807 * @class Roo.bootstrap.Container
808 * @extends Roo.bootstrap.Component
809 * Bootstrap Container class
810 * @cfg {Boolean} jumbotron is it a jumbotron element
811 * @cfg {String} html content of element
812 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
813 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
814 * @cfg {String} header content of header (for panel)
815 * @cfg {String} footer content of footer (for panel)
816 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
819 * Create a new Container
820 * @param {Object} config The config object
823 Roo.bootstrap.Container = function(config){
824 Roo.bootstrap.Container.superclass.constructor.call(this, config);
827 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
837 getChildContainer : function() {
843 if (this.panel.length) {
844 return this.el.select('.panel-body',true).first();
851 getAutoCreate : function(){
857 if (this.jumbotron) {
858 cfg.cls = 'jumbotron';
861 cfg.cls = this.cls + '';
864 if (this.sticky.length) {
866 var bd = Roo.get(document.body);
867 if (!bd.hasClass('bootstrap-sticky')) {
868 bd.addClass('bootstrap-sticky');
869 Roo.select('html',true).setStyle('height', '100%');
872 cfg.cls += 'bootstrap-sticky-' + this.sticky;
876 if (this.well.length) {
880 cfg.cls +=' well well-' +this.well;
890 if (this.panel.length) {
891 cfg.cls += ' panel panel-' + this.panel;
893 if (this.header.length) {
896 cls : 'panel-heading',
912 if (this.footer.length) {
914 cls : 'panel-footer',
922 body.html = this.html || cfg.html;
924 if (!cfg.cls.length) {
925 cfg.cls = 'container';
942 * @class Roo.bootstrap.Img
943 * @extends Roo.bootstrap.Component
944 * Bootstrap Img class
945 * @cfg {Boolean} imgResponsive false | true
946 * @cfg {String} border rounded | circle | thumbnail
947 * @cfg {String} src image source
948 * @cfg {String} alt image alternative text
949 * @cfg {String} href a tag href
950 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
954 * @param {Object} config The config object
957 Roo.bootstrap.Img = function(config){
958 Roo.bootstrap.Img.superclass.constructor.call(this, config);
964 * The img click event for the img.
965 * @param {Roo.EventObject} e
971 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
979 getAutoCreate : function(){
983 cls: (this.imgResponsive) ? 'img-responsive' : '',
987 cfg.html = this.html || cfg.html;
989 cfg.src = this.src || cfg.src;
991 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
992 cfg.cls += ' img-' + this.border;
1009 a.target = this.target;
1015 return (this.href) ? a : cfg;
1018 initEvents: function() {
1021 this.el.on('click', this.onClick, this);
1025 onClick : function(e)
1027 Roo.log('img onclick');
1028 this.fireEvent('click', this, e);
1041 * @class Roo.bootstrap.Header
1042 * @extends Roo.bootstrap.Component
1043 * Bootstrap Header class
1044 * @cfg {String} html content of header
1045 * @cfg {Number} level (1|2|3|4|5|6) default 1
1048 * Create a new Header
1049 * @param {Object} config The config object
1053 Roo.bootstrap.Header = function(config){
1054 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1057 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1065 getAutoCreate : function(){
1068 tag: 'h' + (1 *this.level),
1069 html: this.html || 'fill in html'
1081 * Ext JS Library 1.1.1
1082 * Copyright(c) 2006-2007, Ext JS, LLC.
1084 * Originally Released Under LGPL - original licence link has changed is not relivant.
1087 * <script type="text/javascript">
1091 * @class Roo.bootstrap.MenuMgr
1092 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1095 Roo.bootstrap.MenuMgr = function(){
1096 var menus, active, groups = {}, attached = false, lastShow = new Date();
1098 // private - called when first menu is created
1101 active = new Roo.util.MixedCollection();
1102 Roo.get(document).addKeyListener(27, function(){
1103 if(active.length > 0){
1111 if(active && active.length > 0){
1112 var c = active.clone();
1122 if(active.length < 1){
1123 Roo.get(document).un("mouseup", onMouseDown);
1131 var last = active.last();
1132 lastShow = new Date();
1135 Roo.get(document).on("mouseup", onMouseDown);
1140 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1141 m.parentMenu.activeChild = m;
1142 }else if(last && last.isVisible()){
1143 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1148 function onBeforeHide(m){
1150 m.activeChild.hide();
1152 if(m.autoHideTimer){
1153 clearTimeout(m.autoHideTimer);
1154 delete m.autoHideTimer;
1159 function onBeforeShow(m){
1160 var pm = m.parentMenu;
1161 if(!pm && !m.allowOtherMenus){
1163 }else if(pm && pm.activeChild && active != m){
1164 pm.activeChild.hide();
1169 function onMouseDown(e){
1170 Roo.log("on MouseDown");
1171 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1179 function onBeforeCheck(mi, state){
1181 var g = groups[mi.group];
1182 for(var i = 0, l = g.length; i < l; i++){
1184 g[i].setChecked(false);
1193 * Hides all menus that are currently visible
1195 hideAll : function(){
1200 register : function(menu){
1204 menus[menu.id] = menu;
1205 menu.on("beforehide", onBeforeHide);
1206 menu.on("hide", onHide);
1207 menu.on("beforeshow", onBeforeShow);
1208 menu.on("show", onShow);
1210 if(g && menu.events["checkchange"]){
1214 groups[g].push(menu);
1215 menu.on("checkchange", onCheck);
1220 * Returns a {@link Roo.menu.Menu} object
1221 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1222 * be used to generate and return a new Menu instance.
1224 get : function(menu){
1225 if(typeof menu == "string"){ // menu id
1227 }else if(menu.events){ // menu instance
1230 /*else if(typeof menu.length == 'number'){ // array of menu items?
1231 return new Roo.bootstrap.Menu({items:menu});
1232 }else{ // otherwise, must be a config
1233 return new Roo.bootstrap.Menu(menu);
1240 unregister : function(menu){
1241 delete menus[menu.id];
1242 menu.un("beforehide", onBeforeHide);
1243 menu.un("hide", onHide);
1244 menu.un("beforeshow", onBeforeShow);
1245 menu.un("show", onShow);
1247 if(g && menu.events["checkchange"]){
1248 groups[g].remove(menu);
1249 menu.un("checkchange", onCheck);
1254 registerCheckable : function(menuItem){
1255 var g = menuItem.group;
1260 groups[g].push(menuItem);
1261 menuItem.on("beforecheckchange", onBeforeCheck);
1266 unregisterCheckable : function(menuItem){
1267 var g = menuItem.group;
1269 groups[g].remove(menuItem);
1270 menuItem.un("beforecheckchange", onBeforeCheck);
1282 * @class Roo.bootstrap.Menu
1283 * @extends Roo.bootstrap.Component
1284 * Bootstrap Menu class - container for MenuItems
1285 * @cfg {String} type type of menu
1289 * @param {Object} config The config object
1293 Roo.bootstrap.Menu = function(config){
1294 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1295 if (this.registerMenu) {
1296 Roo.bootstrap.MenuMgr.register(this);
1301 * Fires before this menu is displayed
1302 * @param {Roo.menu.Menu} this
1307 * Fires before this menu is hidden
1308 * @param {Roo.menu.Menu} this
1313 * Fires after this menu is displayed
1314 * @param {Roo.menu.Menu} this
1319 * Fires after this menu is hidden
1320 * @param {Roo.menu.Menu} this
1325 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1326 * @param {Roo.menu.Menu} this
1327 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1328 * @param {Roo.EventObject} e
1333 * Fires when the mouse is hovering over this menu
1334 * @param {Roo.menu.Menu} this
1335 * @param {Roo.EventObject} e
1336 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1341 * Fires when the mouse exits this menu
1342 * @param {Roo.menu.Menu} this
1343 * @param {Roo.EventObject} e
1344 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1349 * Fires when a menu item contained in this menu is clicked
1350 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1351 * @param {Roo.EventObject} e
1355 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1358 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1362 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1365 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1367 registerMenu : true,
1369 menuItems :false, // stores the menu items..
1375 getChildContainer : function() {
1379 getAutoCreate : function(){
1381 //if (['right'].indexOf(this.align)!==-1) {
1382 // cfg.cn[1].cls += ' pull-right'
1386 cls : 'dropdown-menu' ,
1387 style : 'z-index:1000'
1391 if (this.type === 'submenu') {
1392 cfg.cls = 'submenu active'
1397 initEvents : function() {
1399 // Roo.log("ADD event");
1400 // Roo.log(this.triggerEl.dom);
1401 this.triggerEl.on('click', this.onTriggerPress, this);
1402 this.triggerEl.addClass('dropdown-toggle');
1403 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1405 this.el.on("mouseover", this.onMouseOver, this);
1406 this.el.on("mouseout", this.onMouseOut, this);
1410 findTargetItem : function(e){
1411 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1415 //Roo.log(t); Roo.log(t.id);
1417 //Roo.log(this.menuitems);
1418 return this.menuitems.get(t.id);
1420 //return this.items.get(t.menuItemId);
1425 onClick : function(e){
1426 Roo.log("menu.onClick");
1427 var t = this.findTargetItem(e);
1433 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1434 if(t == this.activeItem && t.shouldDeactivate(e)){
1435 this.activeItem.deactivate();
1436 delete this.activeItem;
1440 this.setActiveItem(t, true);
1447 Roo.log('pass click event');
1451 this.fireEvent("click", this, t, e);
1455 onMouseOver : function(e){
1456 var t = this.findTargetItem(e);
1459 // if(t.canActivate && !t.disabled){
1460 // this.setActiveItem(t, true);
1464 this.fireEvent("mouseover", this, e, t);
1466 isVisible : function(){
1467 return !this.hidden;
1469 onMouseOut : function(e){
1470 var t = this.findTargetItem(e);
1473 // if(t == this.activeItem && t.shouldDeactivate(e)){
1474 // this.activeItem.deactivate();
1475 // delete this.activeItem;
1478 this.fireEvent("mouseout", this, e, t);
1483 * Displays this menu relative to another element
1484 * @param {String/HTMLElement/Roo.Element} element The element to align to
1485 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1486 * the element (defaults to this.defaultAlign)
1487 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1489 show : function(el, pos, parentMenu){
1490 this.parentMenu = parentMenu;
1494 this.fireEvent("beforeshow", this);
1495 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1498 * Displays this menu at a specific xy position
1499 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1500 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1502 showAt : function(xy, parentMenu, /* private: */_e){
1503 this.parentMenu = parentMenu;
1508 this.fireEvent("beforeshow", this);
1510 //xy = this.el.adjustForConstraints(xy);
1512 //this.el.setXY(xy);
1514 this.hideMenuItems();
1515 this.hidden = false;
1516 this.triggerEl.addClass('open');
1518 this.fireEvent("show", this);
1524 this.doFocus.defer(50, this);
1528 doFocus : function(){
1530 this.focusEl.focus();
1535 * Hides this menu and optionally all parent menus
1536 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1538 hide : function(deep){
1540 this.hideMenuItems();
1541 if(this.el && this.isVisible()){
1542 this.fireEvent("beforehide", this);
1543 if(this.activeItem){
1544 this.activeItem.deactivate();
1545 this.activeItem = null;
1547 this.triggerEl.removeClass('open');;
1549 this.fireEvent("hide", this);
1551 if(deep === true && this.parentMenu){
1552 this.parentMenu.hide(true);
1556 onTriggerPress : function(e)
1559 Roo.log('trigger press');
1560 //Roo.log(e.getTarget());
1561 // Roo.log(this.triggerEl.dom);
1562 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1565 if (this.isVisible()) {
1569 this.show(this.triggerEl, false, false);
1578 hideMenuItems : function()
1580 //$(backdrop).remove()
1581 Roo.select('.open',true).each(function(aa) {
1583 aa.removeClass('open');
1584 //var parent = getParent($(this))
1585 //var relatedTarget = { relatedTarget: this }
1587 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1588 //if (e.isDefaultPrevented()) return
1589 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1592 addxtypeChild : function (tree, cntr) {
1593 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1595 this.menuitems.add(comp);
1616 * @class Roo.bootstrap.MenuItem
1617 * @extends Roo.bootstrap.Component
1618 * Bootstrap MenuItem class
1619 * @cfg {String} html the menu label
1620 * @cfg {String} href the link
1621 * @cfg {Boolean} preventDefault (true | false) default true
1625 * Create a new MenuItem
1626 * @param {Object} config The config object
1630 Roo.bootstrap.MenuItem = function(config){
1631 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1636 * The raw click event for the entire grid.
1637 * @param {Roo.EventObject} e
1643 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1647 preventDefault: true,
1649 getAutoCreate : function(){
1652 cls: 'dropdown-menu-item',
1662 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1663 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1667 initEvents: function() {
1669 //this.el.select('a').on('click', this.onClick, this);
1672 onClick : function(e)
1674 Roo.log('item on click ');
1675 //if(this.preventDefault){
1676 // e.preventDefault();
1678 //this.parent().hideMenuItems();
1680 this.fireEvent('click', this, e);
1699 * @class Roo.bootstrap.MenuSeparator
1700 * @extends Roo.bootstrap.Component
1701 * Bootstrap MenuSeparator class
1704 * Create a new MenuItem
1705 * @param {Object} config The config object
1709 Roo.bootstrap.MenuSeparator = function(config){
1710 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1713 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1715 getAutoCreate : function(){
1730 <div class="modal fade">
1731 <div class="modal-dialog">
1732 <div class="modal-content">
1733 <div class="modal-header">
1734 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1735 <h4 class="modal-title">Modal title</h4>
1737 <div class="modal-body">
1738 <p>One fine body…</p>
1740 <div class="modal-footer">
1741 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1742 <button type="button" class="btn btn-primary">Save changes</button>
1744 </div><!-- /.modal-content -->
1745 </div><!-- /.modal-dialog -->
1746 </div><!-- /.modal -->
1756 * @class Roo.bootstrap.Modal
1757 * @extends Roo.bootstrap.Component
1758 * Bootstrap Modal class
1759 * @cfg {String} title Title of dialog
1760 * @cfg {Boolean} specificTitle (true|false) default false
1761 * @cfg {Array} buttons Array of buttons or standard button set..
1764 * Create a new Modal Dialog
1765 * @param {Object} config The config object
1768 Roo.bootstrap.Modal = function(config){
1769 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1774 * The raw btnclick event for the button
1775 * @param {Roo.EventObject} e
1779 this.buttons = this.buttons || [];
1782 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1784 title : 'test dialog',
1791 specificTitle: false,
1793 onRender : function(ct, position)
1795 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1798 var cfg = Roo.apply({}, this.getAutoCreate());
1801 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1803 //if (!cfg.name.length) {
1807 cfg.cls += ' ' + this.cls;
1810 cfg.style = this.style;
1812 this.el = Roo.get(document.body).createChild(cfg, position);
1814 //var type = this.el.dom.type;
1816 if(this.tabIndex !== undefined){
1817 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1822 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1823 this.maskEl.enableDisplayMode("block");
1825 //this.el.addClass("x-dlg-modal");
1827 if (this.buttons.length) {
1828 Roo.each(this.buttons, function(bb) {
1829 b = Roo.apply({}, bb);
1830 b.xns = b.xns || Roo.bootstrap;
1831 b.xtype = b.xtype || 'Button';
1832 if (typeof(b.listeners) == 'undefined') {
1833 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1836 var btn = Roo.factory(b);
1838 btn.onRender(this.el.select('.modal-footer').first());
1842 // render the children.
1845 if(typeof(this.items) != 'undefined'){
1846 var items = this.items;
1849 for(var i =0;i < items.length;i++) {
1850 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1854 this.items = nitems;
1856 this.body = this.el.select('.modal-body',true).first();
1857 this.close = this.el.select('.modal-header .close', true).first();
1858 this.footer = this.el.select('.modal-footer',true).first();
1860 //this.el.addClass([this.fieldClass, this.cls]);
1863 getAutoCreate : function(){
1868 html : this.html || ''
1873 cls : 'modal-title',
1877 if(this.specificTitle){
1883 style : 'display: none',
1886 cls: "modal-dialog",
1889 cls : "modal-content",
1892 cls : 'modal-header',
1904 cls : 'modal-footer'
1920 getChildContainer : function() {
1922 return this.el.select('.modal-body',true).first();
1925 getButtonContainer : function() {
1926 return this.el.select('.modal-footer',true).first();
1929 initEvents : function()
1931 this.el.select('.modal-header .close').on('click', this.hide, this);
1933 // this.addxtype(this);
1937 if (!this.rendered) {
1941 this.el.addClass('on');
1942 this.el.removeClass('fade');
1943 this.el.setStyle('display', 'block');
1944 Roo.get(document.body).addClass("x-body-masked");
1945 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1947 this.el.setStyle('zIndex', '10001');
1948 this.fireEvent('show', this);
1954 Roo.log('Modal hide?!');
1956 Roo.get(document.body).removeClass("x-body-masked");
1957 this.el.removeClass('on');
1958 this.el.addClass('fade');
1959 this.el.setStyle('display', 'none');
1960 this.fireEvent('hide', this);
1963 addButton : function(str, cb)
1967 var b = Roo.apply({}, { html : str } );
1968 b.xns = b.xns || Roo.bootstrap;
1969 b.xtype = b.xtype || 'Button';
1970 if (typeof(b.listeners) == 'undefined') {
1971 b.listeners = { click : cb.createDelegate(this) };
1974 var btn = Roo.factory(b);
1976 btn.onRender(this.el.select('.modal-footer').first());
1982 setDefaultButton : function(btn)
1984 //this.el.select('.modal-footer').()
1986 resizeTo: function(w,h)
1990 setContentSize : function(w, h)
1994 onButtonClick: function(btn,e)
1997 this.fireEvent('btnclick', btn.name, e);
1999 setTitle: function(str) {
2000 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2006 Roo.apply(Roo.bootstrap.Modal, {
2008 * Button config that displays a single OK button
2017 * Button config that displays Yes and No buttons
2033 * Button config that displays OK and Cancel buttons
2048 * Button config that displays Yes, No and Cancel buttons
2070 * messagebox - can be used as a replace
2074 * @class Roo.MessageBox
2075 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2079 Roo.Msg.alert('Status', 'Changes saved successfully.');
2081 // Prompt for user data:
2082 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2084 // process text value...
2088 // Show a dialog using config options:
2090 title:'Save Changes?',
2091 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2092 buttons: Roo.Msg.YESNOCANCEL,
2099 Roo.bootstrap.MessageBox = function(){
2100 var dlg, opt, mask, waitTimer;
2101 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2102 var buttons, activeTextEl, bwidth;
2106 var handleButton = function(button){
2108 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2112 var handleHide = function(){
2114 dlg.el.removeClass(opt.cls);
2117 // Roo.TaskMgr.stop(waitTimer);
2118 // waitTimer = null;
2123 var updateButtons = function(b){
2126 buttons["ok"].hide();
2127 buttons["cancel"].hide();
2128 buttons["yes"].hide();
2129 buttons["no"].hide();
2130 //dlg.footer.dom.style.display = 'none';
2133 dlg.footer.dom.style.display = '';
2134 for(var k in buttons){
2135 if(typeof buttons[k] != "function"){
2138 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2139 width += buttons[k].el.getWidth()+15;
2149 var handleEsc = function(d, k, e){
2150 if(opt && opt.closable !== false){
2160 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2161 * @return {Roo.BasicDialog} The BasicDialog element
2163 getDialog : function(){
2165 dlg = new Roo.bootstrap.Modal( {
2168 //constraintoviewport:false,
2170 //collapsible : false,
2175 //buttonAlign:"center",
2176 closeClick : function(){
2177 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2180 handleButton("cancel");
2185 dlg.on("hide", handleHide);
2187 //dlg.addKeyListener(27, handleEsc);
2189 this.buttons = buttons;
2190 var bt = this.buttonText;
2191 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2192 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2193 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2194 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2196 bodyEl = dlg.body.createChild({
2198 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2199 '<textarea class="roo-mb-textarea"></textarea>' +
2200 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2202 msgEl = bodyEl.dom.firstChild;
2203 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2204 textboxEl.enableDisplayMode();
2205 textboxEl.addKeyListener([10,13], function(){
2206 if(dlg.isVisible() && opt && opt.buttons){
2209 }else if(opt.buttons.yes){
2210 handleButton("yes");
2214 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2215 textareaEl.enableDisplayMode();
2216 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2217 progressEl.enableDisplayMode();
2218 var pf = progressEl.dom.firstChild;
2220 pp = Roo.get(pf.firstChild);
2221 pp.setHeight(pf.offsetHeight);
2229 * Updates the message box body text
2230 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2231 * the XHTML-compliant non-breaking space character '&#160;')
2232 * @return {Roo.MessageBox} This message box
2234 updateText : function(text){
2235 if(!dlg.isVisible() && !opt.width){
2236 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2238 msgEl.innerHTML = text || ' ';
2240 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2241 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2243 Math.min(opt.width || cw , this.maxWidth),
2244 Math.max(opt.minWidth || this.minWidth, bwidth)
2247 activeTextEl.setWidth(w);
2249 if(dlg.isVisible()){
2250 dlg.fixedcenter = false;
2252 // to big, make it scroll. = But as usual stupid IE does not support
2255 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2256 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2257 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2259 bodyEl.dom.style.height = '';
2260 bodyEl.dom.style.overflowY = '';
2263 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2265 bodyEl.dom.style.overflowX = '';
2268 dlg.setContentSize(w, bodyEl.getHeight());
2269 if(dlg.isVisible()){
2270 dlg.fixedcenter = true;
2276 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2277 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2278 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2279 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2280 * @return {Roo.MessageBox} This message box
2282 updateProgress : function(value, text){
2284 this.updateText(text);
2286 if (pp) { // weird bug on my firefox - for some reason this is not defined
2287 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2293 * Returns true if the message box is currently displayed
2294 * @return {Boolean} True if the message box is visible, else false
2296 isVisible : function(){
2297 return dlg && dlg.isVisible();
2301 * Hides the message box if it is displayed
2304 if(this.isVisible()){
2310 * Displays a new message box, or reinitializes an existing message box, based on the config options
2311 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2312 * The following config object properties are supported:
2314 Property Type Description
2315 ---------- --------------- ------------------------------------------------------------------------------------
2316 animEl String/Element An id or Element from which the message box should animate as it opens and
2317 closes (defaults to undefined)
2318 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2319 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2320 closable Boolean False to hide the top-right close button (defaults to true). Note that
2321 progress and wait dialogs will ignore this property and always hide the
2322 close button as they can only be closed programmatically.
2323 cls String A custom CSS class to apply to the message box element
2324 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2325 displayed (defaults to 75)
2326 fn Function A callback function to execute after closing the dialog. The arguments to the
2327 function will be btn (the name of the button that was clicked, if applicable,
2328 e.g. "ok"), and text (the value of the active text field, if applicable).
2329 Progress and wait dialogs will ignore this option since they do not respond to
2330 user actions and can only be closed programmatically, so any required function
2331 should be called by the same code after it closes the dialog.
2332 icon String A CSS class that provides a background image to be used as an icon for
2333 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2334 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2335 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2336 modal Boolean False to allow user interaction with the page while the message box is
2337 displayed (defaults to true)
2338 msg String A string that will replace the existing message box body text (defaults
2339 to the XHTML-compliant non-breaking space character ' ')
2340 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2341 progress Boolean True to display a progress bar (defaults to false)
2342 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2343 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2344 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2345 title String The title text
2346 value String The string value to set into the active textbox element if displayed
2347 wait Boolean True to display a progress bar (defaults to false)
2348 width Number The width of the dialog in pixels
2355 msg: 'Please enter your address:',
2357 buttons: Roo.MessageBox.OKCANCEL,
2360 animEl: 'addAddressBtn'
2363 * @param {Object} config Configuration options
2364 * @return {Roo.MessageBox} This message box
2366 show : function(options)
2369 // this causes nightmares if you show one dialog after another
2370 // especially on callbacks..
2372 if(this.isVisible()){
2375 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2376 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2377 Roo.log("New Dialog Message:" + options.msg )
2378 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2379 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2382 var d = this.getDialog();
2384 d.setTitle(opt.title || " ");
2385 d.close.setDisplayed(opt.closable !== false);
2386 activeTextEl = textboxEl;
2387 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2392 textareaEl.setHeight(typeof opt.multiline == "number" ?
2393 opt.multiline : this.defaultTextHeight);
2394 activeTextEl = textareaEl;
2403 progressEl.setDisplayed(opt.progress === true);
2404 this.updateProgress(0);
2405 activeTextEl.dom.value = opt.value || "";
2407 dlg.setDefaultButton(activeTextEl);
2409 var bs = opt.buttons;
2413 }else if(bs && bs.yes){
2414 db = buttons["yes"];
2416 dlg.setDefaultButton(db);
2418 bwidth = updateButtons(opt.buttons);
2419 this.updateText(opt.msg);
2421 d.el.addClass(opt.cls);
2423 d.proxyDrag = opt.proxyDrag === true;
2424 d.modal = opt.modal !== false;
2425 d.mask = opt.modal !== false ? mask : false;
2427 // force it to the end of the z-index stack so it gets a cursor in FF
2428 document.body.appendChild(dlg.el.dom);
2429 d.animateTarget = null;
2430 d.show(options.animEl);
2436 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2437 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2438 * and closing the message box when the process is complete.
2439 * @param {String} title The title bar text
2440 * @param {String} msg The message box body text
2441 * @return {Roo.MessageBox} This message box
2443 progress : function(title, msg){
2450 minWidth: this.minProgressWidth,
2457 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2458 * If a callback function is passed it will be called after the user clicks the button, and the
2459 * id of the button that was clicked will be passed as the only parameter to the callback
2460 * (could also be the top-right close button).
2461 * @param {String} title The title bar text
2462 * @param {String} msg The message box body text
2463 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2464 * @param {Object} scope (optional) The scope of the callback function
2465 * @return {Roo.MessageBox} This message box
2467 alert : function(title, msg, fn, scope){
2480 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2481 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2482 * You are responsible for closing the message box when the process is complete.
2483 * @param {String} msg The message box body text
2484 * @param {String} title (optional) The title bar text
2485 * @return {Roo.MessageBox} This message box
2487 wait : function(msg, title){
2498 waitTimer = Roo.TaskMgr.start({
2500 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2508 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2509 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2510 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2511 * @param {String} title The title bar text
2512 * @param {String} msg The message box body text
2513 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2514 * @param {Object} scope (optional) The scope of the callback function
2515 * @return {Roo.MessageBox} This message box
2517 confirm : function(title, msg, fn, scope){
2521 buttons: this.YESNO,
2530 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2531 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2532 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2533 * (could also be the top-right close button) and the text that was entered will be passed as the two
2534 * parameters to the callback.
2535 * @param {String} title The title bar text
2536 * @param {String} msg The message box body text
2537 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2538 * @param {Object} scope (optional) The scope of the callback function
2539 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2540 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2541 * @return {Roo.MessageBox} This message box
2543 prompt : function(title, msg, fn, scope, multiline){
2547 buttons: this.OKCANCEL,
2552 multiline: multiline,
2559 * Button config that displays a single OK button
2564 * Button config that displays Yes and No buttons
2567 YESNO : {yes:true, no:true},
2569 * Button config that displays OK and Cancel buttons
2572 OKCANCEL : {ok:true, cancel:true},
2574 * Button config that displays Yes, No and Cancel buttons
2577 YESNOCANCEL : {yes:true, no:true, cancel:true},
2580 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2583 defaultTextHeight : 75,
2585 * The maximum width in pixels of the message box (defaults to 600)
2590 * The minimum width in pixels of the message box (defaults to 100)
2595 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2596 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2599 minProgressWidth : 250,
2601 * An object containing the default button text strings that can be overriden for localized language support.
2602 * Supported properties are: ok, cancel, yes and no.
2603 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2616 * Shorthand for {@link Roo.MessageBox}
2618 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2619 Roo.Msg = Roo.Msg || Roo.MessageBox;
2628 * @class Roo.bootstrap.Navbar
2629 * @extends Roo.bootstrap.Component
2630 * Bootstrap Navbar class
2631 * @cfg {Boolean} sidebar has side bar
2632 * @cfg {Boolean} bar is a bar?
2633 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2634 * @cfg {String} brand what is brand
2635 * @cfg {Boolean} inverse is inverted color
2636 * @cfg {String} type (nav | pills | tabs)
2637 * @cfg {Boolean} arrangement stacked | justified
2638 * @cfg {String} align (left | right) alignment
2639 * @cfg {String} brand_href href of the brand
2640 * @cfg {Boolean} main (true|false) main nav bar? default false
2641 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2645 * Create a new Navbar
2646 * @param {Object} config The config object
2650 Roo.bootstrap.Navbar = function(config){
2651 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2656 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2675 getAutoCreate : function(){
2680 if (this.sidebar === true) {
2688 if (this.bar === true) {
2696 cls: 'navbar-header',
2701 cls: 'navbar-toggle',
2702 'data-toggle': 'collapse',
2707 html: 'Toggle navigation'
2727 cls: 'collapse navbar-collapse'
2732 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2734 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2735 cfg.cls += ' navbar-' + this.position;
2736 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
2739 if (this.brand !== '') {
2742 href: this.brand_href ? this.brand_href : '#',
2743 cls: 'navbar-brand',
2751 cfg.cls += ' main-nav';
2757 } else if (this.bar === false) {
2760 Roo.log('Property \'bar\' in of Navbar must be either true or false')
2770 if (['tabs','pills'].indexOf(this.type)!==-1) {
2771 cfg.cn[0].cls += ' nav-' + this.type
2773 if (this.type!=='nav') {
2774 Roo.log('nav type must be nav/tabs/pills')
2776 cfg.cn[0].cls += ' navbar-nav'
2779 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2780 cfg.cn[0].cls += ' nav-' + this.arrangement;
2783 if (this.align === 'right') {
2784 cfg.cn[0].cls += ' navbar-right';
2787 cfg.cls += ' navbar-inverse';
2795 initEvents :function ()
2797 //Roo.log(this.el.select('.navbar-toggle',true));
2798 this.el.select('.navbar-toggle',true).on('click', function() {
2799 // Roo.log('click');
2800 this.el.select('.navbar-collapse',true).toggleClass('in');
2808 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2810 var size = this.el.getSize();
2811 this.maskEl.setSize(size.width, size.height);
2812 this.maskEl.enableDisplayMode("block");
2821 getChildContainer : function()
2823 if (this.bar === true) {
2824 return this.el.select('.collapse',true).first();
2856 * @class Roo.bootstrap.NavGroup
2857 * @extends Roo.bootstrap.Component
2858 * Bootstrap NavGroup class
2859 * @cfg {String} align left | right
2860 * @cfg {Boolean} inverse false | true
2861 * @cfg {String} type (nav|pills|tab) default nav
2862 * @cfg {String} navId - reference Id for navbar.
2866 * Create a new nav group
2867 * @param {Object} config The config object
2870 Roo.bootstrap.NavGroup = function(config){
2871 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
2873 Roo.bootstrap.NavGroup.register(this);
2877 * Fires when the active item changes
2878 * @param {Roo.bootstrap.NavGroup} this
2879 * @param {Roo.bootstrap.Navbar.Item} item The item selected
2880 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
2887 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
2898 getAutoCreate : function()
2900 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
2907 if (['tabs','pills'].indexOf(this.type)!==-1) {
2908 cfg.cls += ' nav-' + this.type
2910 if (this.type!=='nav') {
2911 Roo.log('nav type must be nav/tabs/pills')
2913 cfg.cls += ' navbar-nav'
2916 if (this.parent().sidebar === true) {
2919 cls: 'dashboard-menu'
2925 if (this.form === true) {
2931 if (this.align === 'right') {
2932 cfg.cls += ' navbar-right';
2934 cfg.cls += ' navbar-left';
2938 if (this.align === 'right') {
2939 cfg.cls += ' navbar-right';
2943 cfg.cls += ' navbar-inverse';
2951 setActiveItem : function(item)
2954 Roo.each(this.navItems, function(v){
2959 v.setActive(false, true);
2966 item.setActive(true, true);
2967 this.fireEvent('changed', this, item, prev);
2973 register : function(item)
2975 this.navItems.push( item);
2976 item.navId = this.navId;
2979 getNavItem: function(tabId)
2982 Roo.each(this.navItems, function(e) {
2983 if (e.tabId == tabId) {
2995 Roo.apply(Roo.bootstrap.NavGroup, {
2999 register : function(navgrp)
3001 this.groups[navgrp.navId] = navgrp;
3004 get: function(navId) {
3005 return this.groups[navId];
3020 * @class Roo.bootstrap.Navbar.Item
3021 * @extends Roo.bootstrap.Component
3022 * Bootstrap Navbar.Button class
3023 * @cfg {String} href link to
3024 * @cfg {String} html content of button
3025 * @cfg {String} badge text inside badge
3026 * @cfg {String} glyphicon name of glyphicon
3027 * @cfg {String} icon name of font awesome icon
3028 * @cfg {Boolean} active Is item active
3029 * @cfg {Boolean} preventDefault (true | false) default false
3030 * @cfg {String} tabId the tab that this item activates.
3033 * Create a new Navbar Button
3034 * @param {Object} config The config object
3036 Roo.bootstrap.Navbar.Item = function(config){
3037 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3042 * The raw click event for the entire grid.
3043 * @param {Roo.EventObject} e
3048 * Fires when the active item active state changes
3049 * @param {Roo.bootstrap.Navbar.Item} this
3050 * @param {boolean} state the new state
3058 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3066 preventDefault : false,
3069 getAutoCreate : function(){
3071 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3073 if (this.parent().parent().sidebar === true) {
3086 cfg.cn[0].html = this.html;
3090 this.cls += ' active';
3094 cfg.cn[0].cls += ' dropdown-toggle';
3095 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3099 cfg.cn[0].tag = 'a',
3100 cfg.cn[0].href = this.href;
3103 if (this.glyphicon) {
3104 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3108 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3120 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3130 if (this.glyphicon) {
3131 if(cfg.html){cfg.html = ' ' + this.html};
3135 cls: 'glyphicon glyphicon-' + this.glyphicon
3140 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3145 cfg.cn[0].html += " <span class='caret'></span>";
3146 //}else if (!this.href) {
3147 // cfg.cn[0].tag='p';
3148 // cfg.cn[0].cls='navbar-text';
3151 cfg.cn[0].href=this.href||'#';
3152 cfg.cn[0].html=this.html;
3155 if (this.badge !== '') {
3158 cfg.cn[0].html + ' ',
3169 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3174 initEvents: function() {
3175 // Roo.log('init events?');
3176 // Roo.log(this.el.dom);
3177 this.el.select('a',true).on('click', this.onClick, this);
3178 // at this point parent should be available..
3179 this.parent().register(this);
3182 onClick : function(e)
3184 if(this.preventDefault){
3188 if(this.fireEvent('click', this, e) === false){
3192 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3193 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3194 this.parent().setActiveItem(this);
3202 isActive: function () {
3205 setActive : function(state, fire)
3207 this.active = state;
3209 this.el.removeClass('active');
3210 } else if (!this.el.hasClass('active')) {
3211 this.el.addClass('active');
3214 this.fireEvent('changed', this, state);
3219 // this should not be here...
3232 * @class Roo.bootstrap.Row
3233 * @extends Roo.bootstrap.Component
3234 * Bootstrap Row class (contains columns...)
3238 * @param {Object} config The config object
3241 Roo.bootstrap.Row = function(config){
3242 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3245 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3247 getAutoCreate : function(){
3266 * @class Roo.bootstrap.Element
3267 * @extends Roo.bootstrap.Component
3268 * Bootstrap Element class
3269 * @cfg {String} html contents of the element
3270 * @cfg {String} tag tag of the element
3271 * @cfg {String} cls class of the element
3274 * Create a new Element
3275 * @param {Object} config The config object
3278 Roo.bootstrap.Element = function(config){
3279 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3282 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3289 getAutoCreate : function(){
3314 * @class Roo.bootstrap.Pagination
3315 * @extends Roo.bootstrap.Component
3316 * Bootstrap Pagination class
3317 * @cfg {String} size xs | sm | md | lg
3318 * @cfg {Boolean} inverse false | true
3321 * Create a new Pagination
3322 * @param {Object} config The config object
3325 Roo.bootstrap.Pagination = function(config){
3326 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3329 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3335 getAutoCreate : function(){
3341 cfg.cls += ' inverse';
3347 cfg.cls += " " + this.cls;
3365 * @class Roo.bootstrap.PaginationItem
3366 * @extends Roo.bootstrap.Component
3367 * Bootstrap PaginationItem class
3368 * @cfg {String} html text
3369 * @cfg {String} href the link
3370 * @cfg {Boolean} preventDefault (true | false) default true
3371 * @cfg {Boolean} active (true | false) default false
3375 * Create a new PaginationItem
3376 * @param {Object} config The config object
3380 Roo.bootstrap.PaginationItem = function(config){
3381 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3386 * The raw click event for the entire grid.
3387 * @param {Roo.EventObject} e
3393 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3397 preventDefault: true,
3401 getAutoCreate : function(){
3407 href : this.href ? this.href : '#',
3408 html : this.html ? this.html : ''
3418 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3424 initEvents: function() {
3426 this.el.on('click', this.onClick, this);
3429 onClick : function(e)
3431 Roo.log('PaginationItem on click ');
3432 if(this.preventDefault){
3436 this.fireEvent('click', this, e);
3452 * @class Roo.bootstrap.Slider
3453 * @extends Roo.bootstrap.Component
3454 * Bootstrap Slider class
3457 * Create a new Slider
3458 * @param {Object} config The config object
3461 Roo.bootstrap.Slider = function(config){
3462 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3465 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3467 getAutoCreate : function(){
3471 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3475 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3493 * @class Roo.bootstrap.Table
3494 * @extends Roo.bootstrap.Component
3495 * Bootstrap Table class
3496 * @cfg {String} cls table class
3497 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3498 * @cfg {String} bgcolor Specifies the background color for a table
3499 * @cfg {Number} border Specifies whether the table cells should have borders or not
3500 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3501 * @cfg {Number} cellspacing Specifies the space between cells
3502 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3503 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3504 * @cfg {String} sortable Specifies that the table should be sortable
3505 * @cfg {String} summary Specifies a summary of the content of a table
3506 * @cfg {Number} width Specifies the width of a table
3508 * @cfg {boolean} striped Should the rows be alternative striped
3509 * @cfg {boolean} bordered Add borders to the table
3510 * @cfg {boolean} hover Add hover highlighting
3511 * @cfg {boolean} condensed Format condensed
3512 * @cfg {boolean} responsive Format condensed
3518 * Create a new Table
3519 * @param {Object} config The config object
3522 Roo.bootstrap.Table = function(config){
3523 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3526 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3527 this.sm = this.selModel;
3528 this.sm.xmodule = this.xmodule || false;
3530 if (this.cm && typeof(this.cm.config) == 'undefined') {
3531 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
3532 this.cm = this.colModel;
3533 this.cm.xmodule = this.xmodule || false;
3536 this.store= Roo.factory(this.store, Roo.data);
3537 this.ds = this.store;
3538 this.ds.xmodule = this.xmodule || false;
3543 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3565 getAutoCreate : function(){
3566 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3575 cfg.cls += ' table-striped';
3578 cfg.cls += ' table-hover';
3580 if (this.bordered) {
3581 cfg.cls += ' table-bordered';
3583 if (this.condensed) {
3584 cfg.cls += ' table-condensed';
3586 if (this.responsive) {
3587 cfg.cls += ' table-responsive';
3594 cfg.cls+= ' ' +this.cls;
3597 // this lot should be simplifed...
3600 cfg.align=this.align;
3603 cfg.bgcolor=this.bgcolor;
3606 cfg.border=this.border;
3608 if (this.cellpadding) {
3609 cfg.cellpadding=this.cellpadding;
3611 if (this.cellspacing) {
3612 cfg.cellspacing=this.cellspacing;
3615 cfg.frame=this.frame;
3618 cfg.rules=this.rules;
3620 if (this.sortable) {
3621 cfg.sortable=this.sortable;
3624 cfg.summary=this.summary;
3627 cfg.width=this.width;
3630 if(this.store || this.cm){
3631 cfg.cn.push(this.renderHeader());
3632 cfg.cn.push(this.renderBody());
3633 cfg.cn.push(this.renderFooter());
3635 cfg.cls+= ' TableGrid';
3641 // initTableGrid : function()
3650 // var cm = this.cm;
3652 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3655 // html: cm.getColumnHeader(i)
3659 // cfg.push(header);
3666 initEvents : function()
3668 if(!this.store || !this.cm){
3672 Roo.log('initEvents with ds!!!!');
3676 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3677 e.on('click', _this.sort, _this);
3679 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
3680 // this.maskEl.enableDisplayMode("block");
3681 // this.maskEl.show();
3683 this.store.on('load', this.onLoad, this);
3684 this.store.on('beforeload', this.onBeforeLoad, this);
3692 sort : function(e,el)
3694 var col = Roo.get(el)
3696 if(!col.hasClass('sortable')){
3700 var sort = col.attr('sort');
3703 if(col.hasClass('glyphicon-arrow-up')){
3707 this.store.sortInfo = {field : sort, direction : dir};
3712 renderHeader : function()
3721 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3723 var config = cm.config[i];
3727 html: cm.getColumnHeader(i)
3730 if(typeof(config.dataIndex) != 'undefined'){
3731 c.sort = config.dataIndex;
3734 if(typeof(config.sortable) != 'undefined' && config.sortable){
3738 if(typeof(config.width) != 'undefined'){
3739 c.style = 'width:' + config.width + 'px';
3748 renderBody : function()
3758 renderFooter : function()
3770 Roo.log('ds onload');
3775 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3776 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
3778 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
3779 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
3782 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
3783 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
3787 var tbody = this.el.select('tbody', true).first();
3791 if(this.store.getCount() > 0){
3792 this.store.data.each(function(d){
3798 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3799 var renderer = cm.getRenderer(i);
3800 var config = cm.config[i];
3804 if(typeof(renderer) !== 'undefined'){
3805 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3808 if(typeof(value) === 'object'){
3818 html: (typeof(value) === 'object') ? '' : value
3821 if(typeof(config.width) != 'undefined'){
3822 td.style = 'width:' + config.width + 'px';
3829 tbody.createChild(row);
3837 Roo.each(renders, function(r){
3838 _this.renderColumn(r);
3842 // if(this.loadMask){
3843 // this.maskEl.hide();
3847 onBeforeLoad : function()
3849 Roo.log('ds onBeforeLoad');
3853 // if(this.loadMask){
3854 // this.maskEl.show();
3860 this.el.select('tbody', true).first().dom.innerHTML = '';
3863 getSelectionModel : function(){
3865 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3867 return this.selModel;
3870 renderColumn : function(r)
3873 r.cfg.render(Roo.get(r.id));
3876 Roo.each(r.cfg.cn, function(c){
3881 _this.renderColumn(child);
3898 * @class Roo.bootstrap.TableCell
3899 * @extends Roo.bootstrap.Component
3900 * Bootstrap TableCell class
3901 * @cfg {String} html cell contain text
3902 * @cfg {String} cls cell class
3903 * @cfg {String} tag cell tag (td|th) default td
3904 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3905 * @cfg {String} align Aligns the content in a cell
3906 * @cfg {String} axis Categorizes cells
3907 * @cfg {String} bgcolor Specifies the background color of a cell
3908 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3909 * @cfg {Number} colspan Specifies the number of columns a cell should span
3910 * @cfg {String} headers Specifies one or more header cells a cell is related to
3911 * @cfg {Number} height Sets the height of a cell
3912 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3913 * @cfg {Number} rowspan Sets the number of rows a cell should span
3914 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3915 * @cfg {String} valign Vertical aligns the content in a cell
3916 * @cfg {Number} width Specifies the width of a cell
3919 * Create a new TableCell
3920 * @param {Object} config The config object
3923 Roo.bootstrap.TableCell = function(config){
3924 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3927 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3947 getAutoCreate : function(){
3948 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3968 cfg.align=this.align
3974 cfg.bgcolor=this.bgcolor
3977 cfg.charoff=this.charoff
3980 cfg.colspan=this.colspan
3983 cfg.headers=this.headers
3986 cfg.height=this.height
3989 cfg.nowrap=this.nowrap
3992 cfg.rowspan=this.rowspan
3995 cfg.scope=this.scope
3998 cfg.valign=this.valign
4001 cfg.width=this.width
4020 * @class Roo.bootstrap.TableRow
4021 * @extends Roo.bootstrap.Component
4022 * Bootstrap TableRow class
4023 * @cfg {String} cls row class
4024 * @cfg {String} align Aligns the content in a table row
4025 * @cfg {String} bgcolor Specifies a background color for a table row
4026 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4027 * @cfg {String} valign Vertical aligns the content in a table row
4030 * Create a new TableRow
4031 * @param {Object} config The config object
4034 Roo.bootstrap.TableRow = function(config){
4035 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4038 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4046 getAutoCreate : function(){
4047 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4057 cfg.align = this.align;
4060 cfg.bgcolor = this.bgcolor;
4063 cfg.charoff = this.charoff;
4066 cfg.valign = this.valign;
4084 * @class Roo.bootstrap.TableBody
4085 * @extends Roo.bootstrap.Component
4086 * Bootstrap TableBody class
4087 * @cfg {String} cls element class
4088 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4089 * @cfg {String} align Aligns the content inside the element
4090 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4091 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4094 * Create a new TableBody
4095 * @param {Object} config The config object
4098 Roo.bootstrap.TableBody = function(config){
4099 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4102 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4110 getAutoCreate : function(){
4111 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4125 cfg.align = this.align;
4128 cfg.charoff = this.charoff;
4131 cfg.valign = this.valign;
4138 // initEvents : function()
4145 // this.store = Roo.factory(this.store, Roo.data);
4146 // this.store.on('load', this.onLoad, this);
4148 // this.store.load();
4152 // onLoad: function ()
4154 // this.fireEvent('load', this);
4164 * Ext JS Library 1.1.1
4165 * Copyright(c) 2006-2007, Ext JS, LLC.
4167 * Originally Released Under LGPL - original licence link has changed is not relivant.
4170 * <script type="text/javascript">
4173 // as we use this in bootstrap.
4174 Roo.namespace('Roo.form');
4176 * @class Roo.form.Action
4177 * Internal Class used to handle form actions
4179 * @param {Roo.form.BasicForm} el The form element or its id
4180 * @param {Object} config Configuration options
4185 // define the action interface
4186 Roo.form.Action = function(form, options){
4188 this.options = options || {};
4191 * Client Validation Failed
4194 Roo.form.Action.CLIENT_INVALID = 'client';
4196 * Server Validation Failed
4199 Roo.form.Action.SERVER_INVALID = 'server';
4201 * Connect to Server Failed
4204 Roo.form.Action.CONNECT_FAILURE = 'connect';
4206 * Reading Data from Server Failed
4209 Roo.form.Action.LOAD_FAILURE = 'load';
4211 Roo.form.Action.prototype = {
4213 failureType : undefined,
4214 response : undefined,
4218 run : function(options){
4223 success : function(response){
4228 handleResponse : function(response){
4232 // default connection failure
4233 failure : function(response){
4235 this.response = response;
4236 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4237 this.form.afterAction(this, false);
4240 processResponse : function(response){
4241 this.response = response;
4242 if(!response.responseText){
4245 this.result = this.handleResponse(response);
4249 // utility functions used internally
4250 getUrl : function(appendParams){
4251 var url = this.options.url || this.form.url || this.form.el.dom.action;
4253 var p = this.getParams();
4255 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4261 getMethod : function(){
4262 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4265 getParams : function(){
4266 var bp = this.form.baseParams;
4267 var p = this.options.params;
4269 if(typeof p == "object"){
4270 p = Roo.urlEncode(Roo.applyIf(p, bp));
4271 }else if(typeof p == 'string' && bp){
4272 p += '&' + Roo.urlEncode(bp);
4275 p = Roo.urlEncode(bp);
4280 createCallback : function(){
4282 success: this.success,
4283 failure: this.failure,
4285 timeout: (this.form.timeout*1000),
4286 upload: this.form.fileUpload ? this.success : undefined
4291 Roo.form.Action.Submit = function(form, options){
4292 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4295 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4298 haveProgress : false,
4299 uploadComplete : false,
4301 // uploadProgress indicator.
4302 uploadProgress : function()
4304 if (!this.form.progressUrl) {
4308 if (!this.haveProgress) {
4309 Roo.MessageBox.progress("Uploading", "Uploading");
4311 if (this.uploadComplete) {
4312 Roo.MessageBox.hide();
4316 this.haveProgress = true;
4318 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4320 var c = new Roo.data.Connection();
4322 url : this.form.progressUrl,
4327 success : function(req){
4328 //console.log(data);
4332 rdata = Roo.decode(req.responseText)
4334 Roo.log("Invalid data from server..");
4338 if (!rdata || !rdata.success) {
4340 Roo.MessageBox.alert(Roo.encode(rdata));
4343 var data = rdata.data;
4345 if (this.uploadComplete) {
4346 Roo.MessageBox.hide();
4351 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4352 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4355 this.uploadProgress.defer(2000,this);
4358 failure: function(data) {
4359 Roo.log('progress url failed ');
4370 // run get Values on the form, so it syncs any secondary forms.
4371 this.form.getValues();
4373 var o = this.options;
4374 var method = this.getMethod();
4375 var isPost = method == 'POST';
4376 if(o.clientValidation === false || this.form.isValid()){
4378 if (this.form.progressUrl) {
4379 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4380 (new Date() * 1) + '' + Math.random());
4385 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4386 form:this.form.el.dom,
4387 url:this.getUrl(!isPost),
4389 params:isPost ? this.getParams() : null,
4390 isUpload: this.form.fileUpload
4393 this.uploadProgress();
4395 }else if (o.clientValidation !== false){ // client validation failed
4396 this.failureType = Roo.form.Action.CLIENT_INVALID;
4397 this.form.afterAction(this, false);
4401 success : function(response)
4403 this.uploadComplete= true;
4404 if (this.haveProgress) {
4405 Roo.MessageBox.hide();
4409 var result = this.processResponse(response);
4410 if(result === true || result.success){
4411 this.form.afterAction(this, true);
4415 this.form.markInvalid(result.errors);
4416 this.failureType = Roo.form.Action.SERVER_INVALID;
4418 this.form.afterAction(this, false);
4420 failure : function(response)
4422 this.uploadComplete= true;
4423 if (this.haveProgress) {
4424 Roo.MessageBox.hide();
4427 this.response = response;
4428 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4429 this.form.afterAction(this, false);
4432 handleResponse : function(response){
4433 if(this.form.errorReader){
4434 var rs = this.form.errorReader.read(response);
4437 for(var i = 0, len = rs.records.length; i < len; i++) {
4438 var r = rs.records[i];
4442 if(errors.length < 1){
4446 success : rs.success,
4452 ret = Roo.decode(response.responseText);
4456 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4466 Roo.form.Action.Load = function(form, options){
4467 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4468 this.reader = this.form.reader;
4471 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4476 Roo.Ajax.request(Roo.apply(
4477 this.createCallback(), {
4478 method:this.getMethod(),
4479 url:this.getUrl(false),
4480 params:this.getParams()
4484 success : function(response){
4486 var result = this.processResponse(response);
4487 if(result === true || !result.success || !result.data){
4488 this.failureType = Roo.form.Action.LOAD_FAILURE;
4489 this.form.afterAction(this, false);
4492 this.form.clearInvalid();
4493 this.form.setValues(result.data);
4494 this.form.afterAction(this, true);
4497 handleResponse : function(response){
4498 if(this.form.reader){
4499 var rs = this.form.reader.read(response);
4500 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4502 success : rs.success,
4506 return Roo.decode(response.responseText);
4510 Roo.form.Action.ACTION_TYPES = {
4511 'load' : Roo.form.Action.Load,
4512 'submit' : Roo.form.Action.Submit
4521 * @class Roo.bootstrap.Form
4522 * @extends Roo.bootstrap.Component
4523 * Bootstrap Form class
4524 * @cfg {String} method GET | POST (default POST)
4525 * @cfg {String} labelAlign top | left (default top)
4526 * @cfg {String} align left | right - for navbars
4531 * @param {Object} config The config object
4535 Roo.bootstrap.Form = function(config){
4536 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4539 * @event clientvalidation
4540 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4541 * @param {Form} this
4542 * @param {Boolean} valid true if the form has passed client-side validation
4544 clientvalidation: true,
4546 * @event beforeaction
4547 * Fires before any action is performed. Return false to cancel the action.
4548 * @param {Form} this
4549 * @param {Action} action The action to be performed
4553 * @event actionfailed
4554 * Fires when an action fails.
4555 * @param {Form} this
4556 * @param {Action} action The action that failed
4558 actionfailed : true,
4560 * @event actioncomplete
4561 * Fires when an action is completed.
4562 * @param {Form} this
4563 * @param {Action} action The action that completed
4565 actioncomplete : true
4570 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4573 * @cfg {String} method
4574 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4579 * The URL to use for form actions if one isn't supplied in the action options.
4582 * @cfg {Boolean} fileUpload
4583 * Set to true if this form is a file upload.
4587 * @cfg {Object} baseParams
4588 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
4592 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
4596 * @cfg {Sting} align (left|right) for navbar forms
4601 activeAction : null,
4604 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4605 * element by passing it or its id or mask the form itself by passing in true.
4608 waitMsgTarget : false,
4613 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4614 * element by passing it or its id or mask the form itself by passing in true.
4618 getAutoCreate : function(){
4622 method : this.method || 'POST',
4623 id : this.id || Roo.id(),
4626 if (this.parent().xtype.match(/^Nav/)) {
4627 cfg.cls = 'navbar-form navbar-' + this.align;
4631 if (this.labelAlign == 'left' ) {
4632 cfg.cls += ' form-horizontal';
4638 initEvents : function()
4640 this.el.on('submit', this.onSubmit, this);
4645 onSubmit : function(e){
4650 * Returns true if client-side validation on the form is successful.
4653 isValid : function(){
4654 var items = this.getItems();
4656 items.each(function(f){
4665 * Returns true if any fields in this form have changed since their original load.
4668 isDirty : function(){
4670 var items = this.getItems();
4671 items.each(function(f){
4681 * Performs a predefined action (submit or load) or custom actions you define on this form.
4682 * @param {String} actionName The name of the action type
4683 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
4684 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
4685 * accept other config options):
4687 Property Type Description
4688 ---------------- --------------- ----------------------------------------------------------------------------------
4689 url String The url for the action (defaults to the form's url)
4690 method String The form method to use (defaults to the form's method, or POST if not defined)
4691 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
4692 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
4693 validate the form on the client (defaults to false)
4695 * @return {BasicForm} this
4697 doAction : function(action, options){
4698 if(typeof action == 'string'){
4699 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
4701 if(this.fireEvent('beforeaction', this, action) !== false){
4702 this.beforeAction(action);
4703 action.run.defer(100, action);
4709 beforeAction : function(action){
4710 var o = action.options;
4712 // not really supported yet.. ??
4714 //if(this.waitMsgTarget === true){
4715 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
4716 //}else if(this.waitMsgTarget){
4717 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
4718 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
4720 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
4726 afterAction : function(action, success){
4727 this.activeAction = null;
4728 var o = action.options;
4730 //if(this.waitMsgTarget === true){
4732 //}else if(this.waitMsgTarget){
4733 // this.waitMsgTarget.unmask();
4735 // Roo.MessageBox.updateProgress(1);
4736 // Roo.MessageBox.hide();
4743 Roo.callback(o.success, o.scope, [this, action]);
4744 this.fireEvent('actioncomplete', this, action);
4748 // failure condition..
4749 // we have a scenario where updates need confirming.
4750 // eg. if a locking scenario exists..
4751 // we look for { errors : { needs_confirm : true }} in the response.
4753 (typeof(action.result) != 'undefined') &&
4754 (typeof(action.result.errors) != 'undefined') &&
4755 (typeof(action.result.errors.needs_confirm) != 'undefined')
4758 Roo.log("not supported yet");
4761 Roo.MessageBox.confirm(
4762 "Change requires confirmation",
4763 action.result.errorMsg,
4768 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
4778 Roo.callback(o.failure, o.scope, [this, action]);
4779 // show an error message if no failed handler is set..
4780 if (!this.hasListener('actionfailed')) {
4781 Roo.log("need to add dialog support");
4783 Roo.MessageBox.alert("Error",
4784 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4785 action.result.errorMsg :
4786 "Saving Failed, please check your entries or try again"
4791 this.fireEvent('actionfailed', this, action);
4796 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4797 * @param {String} id The value to search for
4800 findField : function(id){
4801 var items = this.getItems();
4802 var field = items.get(id);
4804 items.each(function(f){
4805 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4812 return field || null;
4815 * Mark fields in this form invalid in bulk.
4816 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4817 * @return {BasicForm} this
4819 markInvalid : function(errors){
4820 if(errors instanceof Array){
4821 for(var i = 0, len = errors.length; i < len; i++){
4822 var fieldError = errors[i];
4823 var f = this.findField(fieldError.id);
4825 f.markInvalid(fieldError.msg);
4831 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4832 field.markInvalid(errors[id]);
4836 //Roo.each(this.childForms || [], function (f) {
4837 // f.markInvalid(errors);
4844 * Set values for fields in this form in bulk.
4845 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4846 * @return {BasicForm} this
4848 setValues : function(values){
4849 if(values instanceof Array){ // array of objects
4850 for(var i = 0, len = values.length; i < len; i++){
4852 var f = this.findField(v.id);
4854 f.setValue(v.value);
4855 if(this.trackResetOnLoad){
4856 f.originalValue = f.getValue();
4860 }else{ // object hash
4863 if(typeof values[id] != 'function' && (field = this.findField(id))){
4865 if (field.setFromData &&
4867 field.displayField &&
4868 // combos' with local stores can
4869 // be queried via setValue()
4870 // to set their value..
4871 (field.store && !field.store.isLocal)
4875 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4876 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4877 field.setFromData(sd);
4880 field.setValue(values[id]);
4884 if(this.trackResetOnLoad){
4885 field.originalValue = field.getValue();
4891 //Roo.each(this.childForms || [], function (f) {
4892 // f.setValues(values);
4899 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4900 * they are returned as an array.
4901 * @param {Boolean} asString
4904 getValues : function(asString){
4905 //if (this.childForms) {
4906 // copy values from the child forms
4907 // Roo.each(this.childForms, function (f) {
4908 // this.setValues(f.getValues());
4914 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4915 if(asString === true){
4918 return Roo.urlDecode(fs);
4922 * Returns the fields in this form as an object with key/value pairs.
4923 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4926 getFieldValues : function(with_hidden)
4928 var items = this.getItems();
4930 items.each(function(f){
4934 var v = f.getValue();
4935 if (f.inputType =='radio') {
4936 if (typeof(ret[f.getName()]) == 'undefined') {
4937 ret[f.getName()] = ''; // empty..
4940 if (!f.el.dom.checked) {
4948 // not sure if this supported any more..
4949 if ((typeof(v) == 'object') && f.getRawValue) {
4950 v = f.getRawValue() ; // dates..
4952 // combo boxes where name != hiddenName...
4953 if (f.name != f.getName()) {
4954 ret[f.name] = f.getRawValue();
4956 ret[f.getName()] = v;
4963 * Clears all invalid messages in this form.
4964 * @return {BasicForm} this
4966 clearInvalid : function(){
4967 var items = this.getItems();
4969 items.each(function(f){
4980 * @return {BasicForm} this
4983 var items = this.getItems();
4984 items.each(function(f){
4988 Roo.each(this.childForms || [], function (f) {
4995 getItems : function()
4997 var r=new Roo.util.MixedCollection(false, function(o){
4998 return o.id || (o.id = Roo.id());
5000 var iter = function(el) {
5007 Roo.each(el.items,function(e) {
5026 * Ext JS Library 1.1.1
5027 * Copyright(c) 2006-2007, Ext JS, LLC.
5029 * Originally Released Under LGPL - original licence link has changed is not relivant.
5032 * <script type="text/javascript">
5035 * @class Roo.form.VTypes
5036 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5039 Roo.form.VTypes = function(){
5040 // closure these in so they are only created once.
5041 var alpha = /^[a-zA-Z_]+$/;
5042 var alphanum = /^[a-zA-Z0-9_]+$/;
5043 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5044 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5046 // All these messages and functions are configurable
5049 * The function used to validate email addresses
5050 * @param {String} value The email address
5052 'email' : function(v){
5053 return email.test(v);
5056 * The error text to display when the email validation function returns false
5059 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5061 * The keystroke filter mask to be applied on email input
5064 'emailMask' : /[a-z0-9_\.\-@]/i,
5067 * The function used to validate URLs
5068 * @param {String} value The URL
5070 'url' : function(v){
5074 * The error text to display when the url validation function returns false
5077 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5080 * The function used to validate alpha values
5081 * @param {String} value The value
5083 'alpha' : function(v){
5084 return alpha.test(v);
5087 * The error text to display when the alpha validation function returns false
5090 'alphaText' : 'This field should only contain letters and _',
5092 * The keystroke filter mask to be applied on alpha input
5095 'alphaMask' : /[a-z_]/i,
5098 * The function used to validate alphanumeric values
5099 * @param {String} value The value
5101 'alphanum' : function(v){
5102 return alphanum.test(v);
5105 * The error text to display when the alphanumeric validation function returns false
5108 'alphanumText' : 'This field should only contain letters, numbers and _',
5110 * The keystroke filter mask to be applied on alphanumeric input
5113 'alphanumMask' : /[a-z0-9_]/i
5123 * @class Roo.bootstrap.Input
5124 * @extends Roo.bootstrap.Component
5125 * Bootstrap Input class
5126 * @cfg {Boolean} disabled is it disabled
5127 * @cfg {String} fieldLabel - the label associated
5128 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5129 * @cfg {String} name name of the input
5130 * @cfg {string} fieldLabel - the label associated
5131 * @cfg {string} inputType - input / file submit ...
5132 * @cfg {string} placeholder - placeholder to put in text.
5133 * @cfg {string} before - input group add on before
5134 * @cfg {string} after - input group add on after
5135 * @cfg {string} size - (lg|sm) or leave empty..
5136 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5137 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5138 * @cfg {Number} md colspan out of 12 for computer-sized screens
5139 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5140 * @cfg {string} value default value of the input
5141 * @cfg {Number} labelWidth set the width of label (0-12)
5142 * @cfg {String} labelAlign (top|left)
5143 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5147 * Create a new Input
5148 * @param {Object} config The config object
5151 Roo.bootstrap.Input = function(config){
5152 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5157 * Fires when this field receives input focus.
5158 * @param {Roo.form.Field} this
5163 * Fires when this field loses input focus.
5164 * @param {Roo.form.Field} this
5169 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5170 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5171 * @param {Roo.form.Field} this
5172 * @param {Roo.EventObject} e The event object
5177 * Fires just before the field blurs if the field value has changed.
5178 * @param {Roo.form.Field} this
5179 * @param {Mixed} newValue The new value
5180 * @param {Mixed} oldValue The original value
5185 * Fires after the field has been marked as invalid.
5186 * @param {Roo.form.Field} this
5187 * @param {String} msg The validation message
5192 * Fires after the field has been validated with no errors.
5193 * @param {Roo.form.Field} this
5198 * Fires after the key up
5199 * @param {Roo.form.Field} this
5200 * @param {Roo.EventObject} e The event Object
5206 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5208 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5209 automatic validation (defaults to "keyup").
5211 validationEvent : "keyup",
5213 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5215 validateOnBlur : true,
5217 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5219 validationDelay : 250,
5221 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5223 focusClass : "x-form-focus", // not needed???
5227 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5229 invalidClass : "has-error",
5232 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5234 selectOnFocus : false,
5237 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5241 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5246 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5248 disableKeyFilter : false,
5251 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5255 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5259 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5261 blankText : "This field is required",
5264 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5268 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5270 maxLength : Number.MAX_VALUE,
5272 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5274 minLengthText : "The minimum length for this field is {0}",
5276 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5278 maxLengthText : "The maximum length for this field is {0}",
5282 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5283 * If available, this function will be called only after the basic validators all return true, and will be passed the
5284 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5288 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5289 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5290 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5294 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5317 parentLabelAlign : function()
5320 while (parent.parent()) {
5321 parent = parent.parent();
5322 if (typeof(parent.labelAlign) !='undefined') {
5323 return parent.labelAlign;
5330 getAutoCreate : function(){
5332 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5338 if(this.inputType != 'hidden'){
5339 cfg.cls = 'form-group' //input-group
5345 type : this.inputType,
5347 cls : 'form-control',
5348 placeholder : this.placeholder || ''
5352 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5353 input.maxLength = this.maxLength;
5356 if (this.disabled) {
5357 input.disabled=true;
5360 if (this.readOnly) {
5361 input.readonly=true;
5365 input.name = this.name;
5368 input.cls += ' input-' + this.size;
5371 ['xs','sm','md','lg'].map(function(size){
5372 if (settings[size]) {
5373 cfg.cls += ' col-' + size + '-' + settings[size];
5377 var inputblock = input;
5379 if (this.before || this.after) {
5382 cls : 'input-group',
5386 inputblock.cn.push({
5388 cls : 'input-group-addon',
5392 inputblock.cn.push(input);
5394 inputblock.cn.push({
5396 cls : 'input-group-addon',
5403 if (align ==='left' && this.fieldLabel.length) {
5404 Roo.log("left and has label");
5410 cls : 'control-label col-sm-' + this.labelWidth,
5411 html : this.fieldLabel
5415 cls : "col-sm-" + (12 - this.labelWidth),
5422 } else if ( this.fieldLabel.length) {
5428 //cls : 'input-group-addon',
5429 html : this.fieldLabel
5439 Roo.log(" no label && no align");
5448 Roo.log('input-parentType: ' + this.parentType);
5450 if (this.parentType === 'Navbar' && this.parent().bar) {
5451 cfg.cls += ' navbar-form';
5459 * return the real input element.
5461 inputEl: function ()
5463 return this.el.select('input.form-control',true).first();
5465 setDisabled : function(v)
5467 var i = this.inputEl().dom;
5469 i.removeAttribute('disabled');
5473 i.setAttribute('disabled','true');
5475 initEvents : function()
5478 this.inputEl().on("keydown" , this.fireKey, this);
5479 this.inputEl().on("focus", this.onFocus, this);
5480 this.inputEl().on("blur", this.onBlur, this);
5482 this.inputEl().relayEvent('keyup', this);
5484 // reference to original value for reset
5485 this.originalValue = this.getValue();
5486 //Roo.form.TextField.superclass.initEvents.call(this);
5487 if(this.validationEvent == 'keyup'){
5488 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5489 this.inputEl().on('keyup', this.filterValidation, this);
5491 else if(this.validationEvent !== false){
5492 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5495 if(this.selectOnFocus){
5496 this.on("focus", this.preFocus, this);
5499 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5500 this.inputEl().on("keypress", this.filterKeys, this);
5503 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5504 this.el.on("click", this.autoSize, this);
5507 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5508 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5512 filterValidation : function(e){
5513 if(!e.isNavKeyPress()){
5514 this.validationTask.delay(this.validationDelay);
5518 * Validates the field value
5519 * @return {Boolean} True if the value is valid, else false
5521 validate : function(){
5522 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5523 if(this.disabled || this.validateValue(this.getRawValue())){
5524 this.clearInvalid();
5532 * Validates a value according to the field's validation rules and marks the field as invalid
5533 * if the validation fails
5534 * @param {Mixed} value The value to validate
5535 * @return {Boolean} True if the value is valid, else false
5537 validateValue : function(value){
5538 if(value.length < 1) { // if it's blank
5539 if(this.allowBlank){
5540 this.clearInvalid();
5543 this.markInvalid(this.blankText);
5547 if(value.length < this.minLength){
5548 this.markInvalid(String.format(this.minLengthText, this.minLength));
5551 if(value.length > this.maxLength){
5552 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5556 var vt = Roo.form.VTypes;
5557 if(!vt[this.vtype](value, this)){
5558 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5562 if(typeof this.validator == "function"){
5563 var msg = this.validator(value);
5565 this.markInvalid(msg);
5569 if(this.regex && !this.regex.test(value)){
5570 this.markInvalid(this.regexText);
5579 fireKey : function(e){
5580 //Roo.log('field ' + e.getKey());
5581 if(e.isNavKeyPress()){
5582 this.fireEvent("specialkey", this, e);
5585 focus : function (selectText){
5587 this.inputEl().focus();
5588 if(selectText === true){
5589 this.inputEl().dom.select();
5595 onFocus : function(){
5596 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5597 // this.el.addClass(this.focusClass);
5600 this.hasFocus = true;
5601 this.startValue = this.getValue();
5602 this.fireEvent("focus", this);
5606 beforeBlur : Roo.emptyFn,
5610 onBlur : function(){
5612 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5613 //this.el.removeClass(this.focusClass);
5615 this.hasFocus = false;
5616 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
5619 var v = this.getValue();
5620 if(String(v) !== String(this.startValue)){
5621 this.fireEvent('change', this, v, this.startValue);
5623 this.fireEvent("blur", this);
5627 * Resets the current field value to the originally loaded value and clears any validation messages
5630 this.setValue(this.originalValue);
5631 this.clearInvalid();
5634 * Returns the name of the field
5635 * @return {Mixed} name The name field
5637 getName: function(){
5641 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
5642 * @return {Mixed} value The field value
5644 getValue : function(){
5645 return this.inputEl().getValue();
5648 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
5649 * @return {Mixed} value The field value
5651 getRawValue : function(){
5652 var v = this.inputEl().getValue();
5658 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
5659 * @param {Mixed} value The value to set
5661 setRawValue : function(v){
5662 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5665 selectText : function(start, end){
5666 var v = this.getRawValue();
5668 start = start === undefined ? 0 : start;
5669 end = end === undefined ? v.length : end;
5670 var d = this.inputEl().dom;
5671 if(d.setSelectionRange){
5672 d.setSelectionRange(start, end);
5673 }else if(d.createTextRange){
5674 var range = d.createTextRange();
5675 range.moveStart("character", start);
5676 range.moveEnd("character", v.length-end);
5683 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
5684 * @param {Mixed} value The value to set
5686 setValue : function(v){
5689 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5695 processValue : function(value){
5696 if(this.stripCharsRe){
5697 var newValue = value.replace(this.stripCharsRe, '');
5698 if(newValue !== value){
5699 this.setRawValue(newValue);
5706 preFocus : function(){
5708 if(this.selectOnFocus){
5709 this.inputEl().dom.select();
5712 filterKeys : function(e){
5714 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
5717 var c = e.getCharCode(), cc = String.fromCharCode(c);
5718 if(Roo.isIE && (e.isSpecialKey() || !cc)){
5721 if(!this.maskRe.test(cc)){
5726 * Clear any invalid styles/messages for this field
5728 clearInvalid : function(){
5730 if(!this.el || this.preventMark){ // not rendered
5733 this.el.removeClass(this.invalidClass);
5735 switch(this.msgTarget){
5737 this.el.dom.qtip = '';
5740 this.el.dom.title = '';
5744 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5749 this.errorIcon.dom.qtip = '';
5750 this.errorIcon.hide();
5751 this.un('resize', this.alignErrorIcon, this);
5755 var t = Roo.getDom(this.msgTarget);
5757 t.style.display = 'none';
5761 this.fireEvent('valid', this);
5764 * Mark this field as invalid
5765 * @param {String} msg The validation message
5767 markInvalid : function(msg){
5768 if(!this.el || this.preventMark){ // not rendered
5771 this.el.addClass(this.invalidClass);
5773 msg = msg || this.invalidText;
5774 switch(this.msgTarget){
5776 this.el.dom.qtip = msg;
5777 this.el.dom.qclass = 'x-form-invalid-tip';
5778 if(Roo.QuickTips){ // fix for floating editors interacting with DND
5779 Roo.QuickTips.enable();
5783 this.el.dom.title = msg;
5787 var elp = this.el.findParent('.x-form-element', 5, true);
5788 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5789 this.errorEl.setWidth(elp.getWidth(true)-20);
5791 this.errorEl.update(msg);
5792 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5795 if(!this.errorIcon){
5796 var elp = this.el.findParent('.x-form-element', 5, true);
5797 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5799 this.alignErrorIcon();
5800 this.errorIcon.dom.qtip = msg;
5801 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5802 this.errorIcon.show();
5803 this.on('resize', this.alignErrorIcon, this);
5806 var t = Roo.getDom(this.msgTarget);
5808 t.style.display = this.msgDisplay;
5812 this.fireEvent('invalid', this, msg);
5815 SafariOnKeyDown : function(event)
5817 // this is a workaround for a password hang bug on chrome/ webkit.
5819 var isSelectAll = false;
5821 if(this.inputEl().dom.selectionEnd > 0){
5822 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5824 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5825 event.preventDefault();
5830 if(isSelectAll){ // backspace and delete key
5832 event.preventDefault();
5833 // this is very hacky as keydown always get's upper case.
5835 var cc = String.fromCharCode(event.getCharCode());
5836 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
5840 adjustWidth : function(tag, w){
5841 tag = tag.toLowerCase();
5842 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
5843 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5847 if(tag == 'textarea'){
5850 }else if(Roo.isOpera){
5854 if(tag == 'textarea'){
5873 * @class Roo.bootstrap.TextArea
5874 * @extends Roo.bootstrap.Input
5875 * Bootstrap TextArea class
5876 * @cfg {Number} cols Specifies the visible width of a text area
5877 * @cfg {Number} rows Specifies the visible number of lines in a text area
5878 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5879 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5880 * @cfg {string} html text
5883 * Create a new TextArea
5884 * @param {Object} config The config object
5887 Roo.bootstrap.TextArea = function(config){
5888 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5892 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5902 getAutoCreate : function(){
5904 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5915 value : this.value || '',
5916 html: this.html || '',
5917 cls : 'form-control',
5918 placeholder : this.placeholder || ''
5922 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5923 input.maxLength = this.maxLength;
5927 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5931 input.cols = this.cols;
5934 if (this.readOnly) {
5935 input.readonly = true;
5939 input.name = this.name;
5943 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5947 ['xs','sm','md','lg'].map(function(size){
5948 if (settings[size]) {
5949 cfg.cls += ' col-' + size + '-' + settings[size];
5953 var inputblock = input;
5955 if (this.before || this.after) {
5958 cls : 'input-group',
5962 inputblock.cn.push({
5964 cls : 'input-group-addon',
5968 inputblock.cn.push(input);
5970 inputblock.cn.push({
5972 cls : 'input-group-addon',
5979 if (align ==='left' && this.fieldLabel.length) {
5980 Roo.log("left and has label");
5986 cls : 'control-label col-sm-' + this.labelWidth,
5987 html : this.fieldLabel
5991 cls : "col-sm-" + (12 - this.labelWidth),
5998 } else if ( this.fieldLabel.length) {
6004 //cls : 'input-group-addon',
6005 html : this.fieldLabel
6015 Roo.log(" no label && no align");
6025 if (this.disabled) {
6026 input.disabled=true;
6033 * return the real textarea element.
6035 inputEl: function ()
6037 return this.el.select('textarea.form-control',true).first();
6045 * trigger field - base class for combo..
6050 * @class Roo.bootstrap.TriggerField
6051 * @extends Roo.bootstrap.Input
6052 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6053 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6054 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6055 * for which you can provide a custom implementation. For example:
6057 var trigger = new Roo.bootstrap.TriggerField();
6058 trigger.onTriggerClick = myTriggerFn;
6059 trigger.applyTo('my-field');
6062 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6063 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6064 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6065 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6067 * Create a new TriggerField.
6068 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6069 * to the base TextField)
6071 Roo.bootstrap.TriggerField = function(config){
6072 this.mimicing = false;
6073 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6076 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6078 * @cfg {String} triggerClass A CSS class to apply to the trigger
6081 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6085 /** @cfg {Boolean} grow @hide */
6086 /** @cfg {Number} growMin @hide */
6087 /** @cfg {Number} growMax @hide */
6093 autoSize: Roo.emptyFn,
6100 actionMode : 'wrap',
6104 getAutoCreate : function(){
6106 var parent = this.parent();
6108 var align = this.parentLabelAlign();
6113 cls: 'form-group' //input-group
6120 type : this.inputType,
6121 cls : 'form-control',
6122 autocomplete: 'off',
6123 placeholder : this.placeholder || ''
6127 input.name = this.name;
6130 input.cls += ' input-' + this.size;
6133 if (this.disabled) {
6134 input.disabled=true;
6137 var inputblock = input;
6139 if (this.before || this.after) {
6142 cls : 'input-group',
6146 inputblock.cn.push({
6148 cls : 'input-group-addon',
6152 inputblock.cn.push(input);
6154 inputblock.cn.push({
6156 cls : 'input-group-addon',
6169 cls: 'form-hidden-field'
6177 Roo.log('multiple');
6185 cls: 'form-hidden-field'
6189 cls: 'select2-choices',
6193 cls: 'select2-search-field',
6206 cls: 'select2-container input-group',
6211 cls: 'typeahead typeahead-long dropdown-menu',
6212 style: 'display:none'
6220 cls : 'input-group-addon btn dropdown-toggle',
6228 cls: 'combobox-clear',
6242 combobox.cls += ' select2-container-multi';
6245 if (align ==='left' && this.fieldLabel.length) {
6247 Roo.log("left and has label");
6253 cls : 'control-label col-sm-' + this.labelWidth,
6254 html : this.fieldLabel
6258 cls : "col-sm-" + (12 - this.labelWidth),
6265 } else if ( this.fieldLabel.length) {
6271 //cls : 'input-group-addon',
6272 html : this.fieldLabel
6282 Roo.log(" no label && no align");
6289 ['xs','sm','md','lg'].map(function(size){
6290 if (settings[size]) {
6291 cfg.cls += ' col-' + size + '-' + settings[size];
6302 onResize : function(w, h){
6303 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6304 // if(typeof w == 'number'){
6305 // var x = w - this.trigger.getWidth();
6306 // this.inputEl().setWidth(this.adjustWidth('input', x));
6307 // this.trigger.setStyle('left', x+'px');
6312 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6315 getResizeEl : function(){
6316 return this.inputEl();
6320 getPositionEl : function(){
6321 return this.inputEl();
6325 alignErrorIcon : function(){
6326 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6330 initEvents : function(){
6332 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6333 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6335 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6336 if(this.hideTrigger){
6337 this.trigger.setDisplayed(false);
6339 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6343 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6346 //this.trigger.addClassOnOver('x-form-trigger-over');
6347 //this.trigger.addClassOnClick('x-form-trigger-click');
6350 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6355 initTrigger : function(){
6360 onDestroy : function(){
6362 this.trigger.removeAllListeners();
6363 // this.trigger.remove();
6366 // this.wrap.remove();
6368 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6372 onFocus : function(){
6373 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6376 this.wrap.addClass('x-trigger-wrap-focus');
6377 this.mimicing = true;
6378 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6379 if(this.monitorTab){
6380 this.el.on("keydown", this.checkTab, this);
6387 checkTab : function(e){
6388 if(e.getKey() == e.TAB){
6394 onBlur : function(){
6399 mimicBlur : function(e, t){
6401 if(!this.wrap.contains(t) && this.validateBlur()){
6408 triggerBlur : function(){
6409 this.mimicing = false;
6410 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6411 if(this.monitorTab){
6412 this.el.un("keydown", this.checkTab, this);
6414 //this.wrap.removeClass('x-trigger-wrap-focus');
6415 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6419 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6420 validateBlur : function(e, t){
6425 onDisable : function(){
6426 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6428 // this.wrap.addClass('x-item-disabled');
6433 onEnable : function(){
6434 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6436 // this.el.removeClass('x-item-disabled');
6441 onShow : function(){
6442 var ae = this.getActionEl();
6445 ae.dom.style.display = '';
6446 ae.dom.style.visibility = 'visible';
6452 onHide : function(){
6453 var ae = this.getActionEl();
6454 ae.dom.style.display = 'none';
6458 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6459 * by an implementing function.
6461 * @param {EventObject} e
6463 onTriggerClick : Roo.emptyFn
6467 * Ext JS Library 1.1.1
6468 * Copyright(c) 2006-2007, Ext JS, LLC.
6470 * Originally Released Under LGPL - original licence link has changed is not relivant.
6473 * <script type="text/javascript">
6478 * @class Roo.data.SortTypes
6480 * Defines the default sorting (casting?) comparison functions used when sorting data.
6482 Roo.data.SortTypes = {
6484 * Default sort that does nothing
6485 * @param {Mixed} s The value being converted
6486 * @return {Mixed} The comparison value
6493 * The regular expression used to strip tags
6497 stripTagsRE : /<\/?[^>]+>/gi,
6500 * Strips all HTML tags to sort on text only
6501 * @param {Mixed} s The value being converted
6502 * @return {String} The comparison value
6504 asText : function(s){
6505 return String(s).replace(this.stripTagsRE, "");
6509 * Strips all HTML tags to sort on text only - Case insensitive
6510 * @param {Mixed} s The value being converted
6511 * @return {String} The comparison value
6513 asUCText : function(s){
6514 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6518 * Case insensitive string
6519 * @param {Mixed} s The value being converted
6520 * @return {String} The comparison value
6522 asUCString : function(s) {
6523 return String(s).toUpperCase();
6528 * @param {Mixed} s The value being converted
6529 * @return {Number} The comparison value
6531 asDate : function(s) {
6535 if(s instanceof Date){
6538 return Date.parse(String(s));
6543 * @param {Mixed} s The value being converted
6544 * @return {Float} The comparison value
6546 asFloat : function(s) {
6547 var val = parseFloat(String(s).replace(/,/g, ""));
6548 if(isNaN(val)) val = 0;
6554 * @param {Mixed} s The value being converted
6555 * @return {Number} The comparison value
6557 asInt : function(s) {
6558 var val = parseInt(String(s).replace(/,/g, ""));
6559 if(isNaN(val)) val = 0;
6564 * Ext JS Library 1.1.1
6565 * Copyright(c) 2006-2007, Ext JS, LLC.
6567 * Originally Released Under LGPL - original licence link has changed is not relivant.
6570 * <script type="text/javascript">
6574 * @class Roo.data.Record
6575 * Instances of this class encapsulate both record <em>definition</em> information, and record
6576 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
6577 * to access Records cached in an {@link Roo.data.Store} object.<br>
6579 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
6580 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
6583 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
6585 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
6586 * {@link #create}. The parameters are the same.
6587 * @param {Array} data An associative Array of data values keyed by the field name.
6588 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
6589 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
6590 * not specified an integer id is generated.
6592 Roo.data.Record = function(data, id){
6593 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
6598 * Generate a constructor for a specific record layout.
6599 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
6600 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
6601 * Each field definition object may contain the following properties: <ul>
6602 * <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,
6603 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
6604 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
6605 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
6606 * is being used, then this is a string containing the javascript expression to reference the data relative to
6607 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
6608 * to the data item relative to the record element. If the mapping expression is the same as the field name,
6609 * this may be omitted.</p></li>
6610 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
6611 * <ul><li>auto (Default, implies no conversion)</li>
6616 * <li>date</li></ul></p></li>
6617 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
6618 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
6619 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
6620 * by the Reader into an object that will be stored in the Record. It is passed the
6621 * following parameters:<ul>
6622 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
6624 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
6626 * <br>usage:<br><pre><code>
6627 var TopicRecord = Roo.data.Record.create(
6628 {name: 'title', mapping: 'topic_title'},
6629 {name: 'author', mapping: 'username'},
6630 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
6631 {name: 'lastPost', mapping: 'post_time', type: 'date'},
6632 {name: 'lastPoster', mapping: 'user2'},
6633 {name: 'excerpt', mapping: 'post_text'}
6636 var myNewRecord = new TopicRecord({
6637 title: 'Do my job please',
6640 lastPost: new Date(),
6641 lastPoster: 'Animal',
6642 excerpt: 'No way dude!'
6644 myStore.add(myNewRecord);
6649 Roo.data.Record.create = function(o){
6651 f.superclass.constructor.apply(this, arguments);
6653 Roo.extend(f, Roo.data.Record);
6654 var p = f.prototype;
6655 p.fields = new Roo.util.MixedCollection(false, function(field){
6658 for(var i = 0, len = o.length; i < len; i++){
6659 p.fields.add(new Roo.data.Field(o[i]));
6661 f.getField = function(name){
6662 return p.fields.get(name);
6667 Roo.data.Record.AUTO_ID = 1000;
6668 Roo.data.Record.EDIT = 'edit';
6669 Roo.data.Record.REJECT = 'reject';
6670 Roo.data.Record.COMMIT = 'commit';
6672 Roo.data.Record.prototype = {
6674 * Readonly flag - true if this record has been modified.
6683 join : function(store){
6688 * Set the named field to the specified value.
6689 * @param {String} name The name of the field to set.
6690 * @param {Object} value The value to set the field to.
6692 set : function(name, value){
6693 if(this.data[name] == value){
6700 if(typeof this.modified[name] == 'undefined'){
6701 this.modified[name] = this.data[name];
6703 this.data[name] = value;
6704 if(!this.editing && this.store){
6705 this.store.afterEdit(this);
6710 * Get the value of the named field.
6711 * @param {String} name The name of the field to get the value of.
6712 * @return {Object} The value of the field.
6714 get : function(name){
6715 return this.data[name];
6719 beginEdit : function(){
6720 this.editing = true;
6725 cancelEdit : function(){
6726 this.editing = false;
6727 delete this.modified;
6731 endEdit : function(){
6732 this.editing = false;
6733 if(this.dirty && this.store){
6734 this.store.afterEdit(this);
6739 * Usually called by the {@link Roo.data.Store} which owns the Record.
6740 * Rejects all changes made to the Record since either creation, or the last commit operation.
6741 * Modified fields are reverted to their original values.
6743 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6744 * of reject operations.
6746 reject : function(){
6747 var m = this.modified;
6749 if(typeof m[n] != "function"){
6750 this.data[n] = m[n];
6754 delete this.modified;
6755 this.editing = false;
6757 this.store.afterReject(this);
6762 * Usually called by the {@link Roo.data.Store} which owns the Record.
6763 * Commits all changes made to the Record since either creation, or the last commit operation.
6765 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6766 * of commit operations.
6768 commit : function(){
6770 delete this.modified;
6771 this.editing = false;
6773 this.store.afterCommit(this);
6778 hasError : function(){
6779 return this.error != null;
6783 clearError : function(){
6788 * Creates a copy of this record.
6789 * @param {String} id (optional) A new record id if you don't want to use this record's id
6792 copy : function(newId) {
6793 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6797 * Ext JS Library 1.1.1
6798 * Copyright(c) 2006-2007, Ext JS, LLC.
6800 * Originally Released Under LGPL - original licence link has changed is not relivant.
6803 * <script type="text/javascript">
6809 * @class Roo.data.Store
6810 * @extends Roo.util.Observable
6811 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6812 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6814 * 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
6815 * has no knowledge of the format of the data returned by the Proxy.<br>
6817 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6818 * instances from the data object. These records are cached and made available through accessor functions.
6820 * Creates a new Store.
6821 * @param {Object} config A config object containing the objects needed for the Store to access data,
6822 * and read the data into Records.
6824 Roo.data.Store = function(config){
6825 this.data = new Roo.util.MixedCollection(false);
6826 this.data.getKey = function(o){
6829 this.baseParams = {};
6836 "multisort" : "_multisort"
6839 if(config && config.data){
6840 this.inlineData = config.data;
6844 Roo.apply(this, config);
6846 if(this.reader){ // reader passed
6847 this.reader = Roo.factory(this.reader, Roo.data);
6848 this.reader.xmodule = this.xmodule || false;
6849 if(!this.recordType){
6850 this.recordType = this.reader.recordType;
6852 if(this.reader.onMetaChange){
6853 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6857 if(this.recordType){
6858 this.fields = this.recordType.prototype.fields;
6864 * @event datachanged
6865 * Fires when the data cache has changed, and a widget which is using this Store
6866 * as a Record cache should refresh its view.
6867 * @param {Store} this
6872 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6873 * @param {Store} this
6874 * @param {Object} meta The JSON metadata
6879 * Fires when Records have been added to the Store
6880 * @param {Store} this
6881 * @param {Roo.data.Record[]} records The array of Records added
6882 * @param {Number} index The index at which the record(s) were added
6887 * Fires when a Record has been removed from the Store
6888 * @param {Store} this
6889 * @param {Roo.data.Record} record The Record that was removed
6890 * @param {Number} index The index at which the record was removed
6895 * Fires when a Record has been updated
6896 * @param {Store} this
6897 * @param {Roo.data.Record} record The Record that was updated
6898 * @param {String} operation The update operation being performed. Value may be one of:
6900 Roo.data.Record.EDIT
6901 Roo.data.Record.REJECT
6902 Roo.data.Record.COMMIT
6908 * Fires when the data cache has been cleared.
6909 * @param {Store} this
6914 * Fires before a request is made for a new data object. If the beforeload handler returns false
6915 * the load action will be canceled.
6916 * @param {Store} this
6917 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6921 * @event beforeloadadd
6922 * Fires after a new set of Records has been loaded.
6923 * @param {Store} this
6924 * @param {Roo.data.Record[]} records The Records that were loaded
6925 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6927 beforeloadadd : true,
6930 * Fires after a new set of Records has been loaded, before they are added to the store.
6931 * @param {Store} this
6932 * @param {Roo.data.Record[]} records The Records that were loaded
6933 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6934 * @params {Object} return from reader
6938 * @event loadexception
6939 * Fires if an exception occurs in the Proxy during loading.
6940 * Called with the signature of the Proxy's "loadexception" event.
6941 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6944 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6945 * @param {Object} load options
6946 * @param {Object} jsonData from your request (normally this contains the Exception)
6948 loadexception : true
6952 this.proxy = Roo.factory(this.proxy, Roo.data);
6953 this.proxy.xmodule = this.xmodule || false;
6954 this.relayEvents(this.proxy, ["loadexception"]);
6956 this.sortToggle = {};
6957 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6959 Roo.data.Store.superclass.constructor.call(this);
6961 if(this.inlineData){
6962 this.loadData(this.inlineData);
6963 delete this.inlineData;
6967 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6969 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6970 * without a remote query - used by combo/forms at present.
6974 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6977 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6980 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6981 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6984 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6985 * on any HTTP request
6988 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6991 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6995 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6996 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7001 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7002 * loaded or when a record is removed. (defaults to false).
7004 pruneModifiedRecords : false,
7010 * Add Records to the Store and fires the add event.
7011 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7013 add : function(records){
7014 records = [].concat(records);
7015 for(var i = 0, len = records.length; i < len; i++){
7016 records[i].join(this);
7018 var index = this.data.length;
7019 this.data.addAll(records);
7020 this.fireEvent("add", this, records, index);
7024 * Remove a Record from the Store and fires the remove event.
7025 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7027 remove : function(record){
7028 var index = this.data.indexOf(record);
7029 this.data.removeAt(index);
7030 if(this.pruneModifiedRecords){
7031 this.modified.remove(record);
7033 this.fireEvent("remove", this, record, index);
7037 * Remove all Records from the Store and fires the clear event.
7039 removeAll : function(){
7041 if(this.pruneModifiedRecords){
7044 this.fireEvent("clear", this);
7048 * Inserts Records to the Store at the given index and fires the add event.
7049 * @param {Number} index The start index at which to insert the passed Records.
7050 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7052 insert : function(index, records){
7053 records = [].concat(records);
7054 for(var i = 0, len = records.length; i < len; i++){
7055 this.data.insert(index, records[i]);
7056 records[i].join(this);
7058 this.fireEvent("add", this, records, index);
7062 * Get the index within the cache of the passed Record.
7063 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7064 * @return {Number} The index of the passed Record. Returns -1 if not found.
7066 indexOf : function(record){
7067 return this.data.indexOf(record);
7071 * Get the index within the cache of the Record with the passed id.
7072 * @param {String} id The id of the Record to find.
7073 * @return {Number} The index of the Record. Returns -1 if not found.
7075 indexOfId : function(id){
7076 return this.data.indexOfKey(id);
7080 * Get the Record with the specified id.
7081 * @param {String} id The id of the Record to find.
7082 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7084 getById : function(id){
7085 return this.data.key(id);
7089 * Get the Record at the specified index.
7090 * @param {Number} index The index of the Record to find.
7091 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7093 getAt : function(index){
7094 return this.data.itemAt(index);
7098 * Returns a range of Records between specified indices.
7099 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7100 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7101 * @return {Roo.data.Record[]} An array of Records
7103 getRange : function(start, end){
7104 return this.data.getRange(start, end);
7108 storeOptions : function(o){
7109 o = Roo.apply({}, o);
7112 this.lastOptions = o;
7116 * Loads the Record cache from the configured Proxy using the configured Reader.
7118 * If using remote paging, then the first load call must specify the <em>start</em>
7119 * and <em>limit</em> properties in the options.params property to establish the initial
7120 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7122 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7123 * and this call will return before the new data has been loaded. Perform any post-processing
7124 * in a callback function, or in a "load" event handler.</strong>
7126 * @param {Object} options An object containing properties which control loading options:<ul>
7127 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7128 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7129 * passed the following arguments:<ul>
7130 * <li>r : Roo.data.Record[]</li>
7131 * <li>options: Options object from the load call</li>
7132 * <li>success: Boolean success indicator</li></ul></li>
7133 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7134 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7137 load : function(options){
7138 options = options || {};
7139 if(this.fireEvent("beforeload", this, options) !== false){
7140 this.storeOptions(options);
7141 var p = Roo.apply(options.params || {}, this.baseParams);
7142 // if meta was not loaded from remote source.. try requesting it.
7143 if (!this.reader.metaFromRemote) {
7146 if(this.sortInfo && this.remoteSort){
7147 var pn = this.paramNames;
7148 p[pn["sort"]] = this.sortInfo.field;
7149 p[pn["dir"]] = this.sortInfo.direction;
7151 if (this.multiSort) {
7152 var pn = this.paramNames;
7153 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7156 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7161 * Reloads the Record cache from the configured Proxy using the configured Reader and
7162 * the options from the last load operation performed.
7163 * @param {Object} options (optional) An object containing properties which may override the options
7164 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7165 * the most recently used options are reused).
7167 reload : function(options){
7168 this.load(Roo.applyIf(options||{}, this.lastOptions));
7172 // Called as a callback by the Reader during a load operation.
7173 loadRecords : function(o, options, success){
7174 if(!o || success === false){
7175 if(success !== false){
7176 this.fireEvent("load", this, [], options, o);
7178 if(options.callback){
7179 options.callback.call(options.scope || this, [], options, false);
7183 // if data returned failure - throw an exception.
7184 if (o.success === false) {
7185 // show a message if no listener is registered.
7186 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7187 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7189 // loadmask wil be hooked into this..
7190 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7193 var r = o.records, t = o.totalRecords || r.length;
7195 this.fireEvent("beforeloadadd", this, r, options, o);
7197 if(!options || options.add !== true){
7198 if(this.pruneModifiedRecords){
7201 for(var i = 0, len = r.length; i < len; i++){
7205 this.data = this.snapshot;
7206 delete this.snapshot;
7209 this.data.addAll(r);
7210 this.totalLength = t;
7212 this.fireEvent("datachanged", this);
7214 this.totalLength = Math.max(t, this.data.length+r.length);
7217 this.fireEvent("load", this, r, options, o);
7218 if(options.callback){
7219 options.callback.call(options.scope || this, r, options, true);
7225 * Loads data from a passed data block. A Reader which understands the format of the data
7226 * must have been configured in the constructor.
7227 * @param {Object} data The data block from which to read the Records. The format of the data expected
7228 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7229 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7231 loadData : function(o, append){
7232 var r = this.reader.readRecords(o);
7233 this.loadRecords(r, {add: append}, true);
7237 * Gets the number of cached records.
7239 * <em>If using paging, this may not be the total size of the dataset. If the data object
7240 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7241 * the data set size</em>
7243 getCount : function(){
7244 return this.data.length || 0;
7248 * Gets the total number of records in the dataset as returned by the server.
7250 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7251 * the dataset size</em>
7253 getTotalCount : function(){
7254 return this.totalLength || 0;
7258 * Returns the sort state of the Store as an object with two properties:
7260 field {String} The name of the field by which the Records are sorted
7261 direction {String} The sort order, "ASC" or "DESC"
7264 getSortState : function(){
7265 return this.sortInfo;
7269 applySort : function(){
7270 if(this.sortInfo && !this.remoteSort){
7271 var s = this.sortInfo, f = s.field;
7272 var st = this.fields.get(f).sortType;
7273 var fn = function(r1, r2){
7274 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7275 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7277 this.data.sort(s.direction, fn);
7278 if(this.snapshot && this.snapshot != this.data){
7279 this.snapshot.sort(s.direction, fn);
7285 * Sets the default sort column and order to be used by the next load operation.
7286 * @param {String} fieldName The name of the field to sort by.
7287 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7289 setDefaultSort : function(field, dir){
7290 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7295 * If remote sorting is used, the sort is performed on the server, and the cache is
7296 * reloaded. If local sorting is used, the cache is sorted internally.
7297 * @param {String} fieldName The name of the field to sort by.
7298 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7300 sort : function(fieldName, dir){
7301 var f = this.fields.get(fieldName);
7303 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7305 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7306 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7311 this.sortToggle[f.name] = dir;
7312 this.sortInfo = {field: f.name, direction: dir};
7313 if(!this.remoteSort){
7315 this.fireEvent("datachanged", this);
7317 this.load(this.lastOptions);
7322 * Calls the specified function for each of the Records in the cache.
7323 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7324 * Returning <em>false</em> aborts and exits the iteration.
7325 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7327 each : function(fn, scope){
7328 this.data.each(fn, scope);
7332 * Gets all records modified since the last commit. Modified records are persisted across load operations
7333 * (e.g., during paging).
7334 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7336 getModifiedRecords : function(){
7337 return this.modified;
7341 createFilterFn : function(property, value, anyMatch){
7342 if(!value.exec){ // not a regex
7343 value = String(value);
7344 if(value.length == 0){
7347 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7350 return value.test(r.data[property]);
7355 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7356 * @param {String} property A field on your records
7357 * @param {Number} start The record index to start at (defaults to 0)
7358 * @param {Number} end The last record index to include (defaults to length - 1)
7359 * @return {Number} The sum
7361 sum : function(property, start, end){
7362 var rs = this.data.items, v = 0;
7364 end = (end || end === 0) ? end : rs.length-1;
7366 for(var i = start; i <= end; i++){
7367 v += (rs[i].data[property] || 0);
7373 * Filter the records by a specified property.
7374 * @param {String} field A field on your records
7375 * @param {String/RegExp} value Either a string that the field
7376 * should start with or a RegExp to test against the field
7377 * @param {Boolean} anyMatch True to match any part not just the beginning
7379 filter : function(property, value, anyMatch){
7380 var fn = this.createFilterFn(property, value, anyMatch);
7381 return fn ? this.filterBy(fn) : this.clearFilter();
7385 * Filter by a function. The specified function will be called with each
7386 * record in this data source. If the function returns true the record is included,
7387 * otherwise it is filtered.
7388 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7389 * @param {Object} scope (optional) The scope of the function (defaults to this)
7391 filterBy : function(fn, scope){
7392 this.snapshot = this.snapshot || this.data;
7393 this.data = this.queryBy(fn, scope||this);
7394 this.fireEvent("datachanged", this);
7398 * Query the records by a specified property.
7399 * @param {String} field A field on your records
7400 * @param {String/RegExp} value Either a string that the field
7401 * should start with or a RegExp to test against the field
7402 * @param {Boolean} anyMatch True to match any part not just the beginning
7403 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7405 query : function(property, value, anyMatch){
7406 var fn = this.createFilterFn(property, value, anyMatch);
7407 return fn ? this.queryBy(fn) : this.data.clone();
7411 * Query by a function. The specified function will be called with each
7412 * record in this data source. If the function returns true the record is included
7414 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7415 * @param {Object} scope (optional) The scope of the function (defaults to this)
7416 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7418 queryBy : function(fn, scope){
7419 var data = this.snapshot || this.data;
7420 return data.filterBy(fn, scope||this);
7424 * Collects unique values for a particular dataIndex from this store.
7425 * @param {String} dataIndex The property to collect
7426 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7427 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7428 * @return {Array} An array of the unique values
7430 collect : function(dataIndex, allowNull, bypassFilter){
7431 var d = (bypassFilter === true && this.snapshot) ?
7432 this.snapshot.items : this.data.items;
7433 var v, sv, r = [], l = {};
7434 for(var i = 0, len = d.length; i < len; i++){
7435 v = d[i].data[dataIndex];
7437 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7446 * Revert to a view of the Record cache with no filtering applied.
7447 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7449 clearFilter : function(suppressEvent){
7450 if(this.snapshot && this.snapshot != this.data){
7451 this.data = this.snapshot;
7452 delete this.snapshot;
7453 if(suppressEvent !== true){
7454 this.fireEvent("datachanged", this);
7460 afterEdit : function(record){
7461 if(this.modified.indexOf(record) == -1){
7462 this.modified.push(record);
7464 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7468 afterReject : function(record){
7469 this.modified.remove(record);
7470 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7474 afterCommit : function(record){
7475 this.modified.remove(record);
7476 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7480 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7481 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7483 commitChanges : function(){
7484 var m = this.modified.slice(0);
7486 for(var i = 0, len = m.length; i < len; i++){
7492 * Cancel outstanding changes on all changed records.
7494 rejectChanges : function(){
7495 var m = this.modified.slice(0);
7497 for(var i = 0, len = m.length; i < len; i++){
7502 onMetaChange : function(meta, rtype, o){
7503 this.recordType = rtype;
7504 this.fields = rtype.prototype.fields;
7505 delete this.snapshot;
7506 this.sortInfo = meta.sortInfo || this.sortInfo;
7508 this.fireEvent('metachange', this, this.reader.meta);
7511 moveIndex : function(data, type)
7513 var index = this.indexOf(data);
7515 var newIndex = index + type;
7519 this.insert(newIndex, data);
7524 * Ext JS Library 1.1.1
7525 * Copyright(c) 2006-2007, Ext JS, LLC.
7527 * Originally Released Under LGPL - original licence link has changed is not relivant.
7530 * <script type="text/javascript">
7534 * @class Roo.data.SimpleStore
7535 * @extends Roo.data.Store
7536 * Small helper class to make creating Stores from Array data easier.
7537 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7538 * @cfg {Array} fields An array of field definition objects, or field name strings.
7539 * @cfg {Array} data The multi-dimensional array of data
7541 * @param {Object} config
7543 Roo.data.SimpleStore = function(config){
7544 Roo.data.SimpleStore.superclass.constructor.call(this, {
7546 reader: new Roo.data.ArrayReader({
7549 Roo.data.Record.create(config.fields)
7551 proxy : new Roo.data.MemoryProxy(config.data)
7555 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7557 * Ext JS Library 1.1.1
7558 * Copyright(c) 2006-2007, Ext JS, LLC.
7560 * Originally Released Under LGPL - original licence link has changed is not relivant.
7563 * <script type="text/javascript">
7568 * @extends Roo.data.Store
7569 * @class Roo.data.JsonStore
7570 * Small helper class to make creating Stores for JSON data easier. <br/>
7572 var store = new Roo.data.JsonStore({
7573 url: 'get-images.php',
7575 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
7578 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
7579 * JsonReader and HttpProxy (unless inline data is provided).</b>
7580 * @cfg {Array} fields An array of field definition objects, or field name strings.
7582 * @param {Object} config
7584 Roo.data.JsonStore = function(c){
7585 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
7586 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
7587 reader: new Roo.data.JsonReader(c, c.fields)
7590 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
7592 * Ext JS Library 1.1.1
7593 * Copyright(c) 2006-2007, Ext JS, LLC.
7595 * Originally Released Under LGPL - original licence link has changed is not relivant.
7598 * <script type="text/javascript">
7602 Roo.data.Field = function(config){
7603 if(typeof config == "string"){
7604 config = {name: config};
7606 Roo.apply(this, config);
7612 var st = Roo.data.SortTypes;
7613 // named sortTypes are supported, here we look them up
7614 if(typeof this.sortType == "string"){
7615 this.sortType = st[this.sortType];
7618 // set default sortType for strings and dates
7622 this.sortType = st.asUCString;
7625 this.sortType = st.asDate;
7628 this.sortType = st.none;
7633 var stripRe = /[\$,%]/g;
7635 // prebuilt conversion function for this field, instead of
7636 // switching every time we're reading a value
7638 var cv, dateFormat = this.dateFormat;
7643 cv = function(v){ return v; };
7646 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
7650 return v !== undefined && v !== null && v !== '' ?
7651 parseInt(String(v).replace(stripRe, ""), 10) : '';
7656 return v !== undefined && v !== null && v !== '' ?
7657 parseFloat(String(v).replace(stripRe, ""), 10) : '';
7662 cv = function(v){ return v === true || v === "true" || v == 1; };
7669 if(v instanceof Date){
7673 if(dateFormat == "timestamp"){
7674 return new Date(v*1000);
7676 return Date.parseDate(v, dateFormat);
7678 var parsed = Date.parse(v);
7679 return parsed ? new Date(parsed) : null;
7688 Roo.data.Field.prototype = {
7696 * Ext JS Library 1.1.1
7697 * Copyright(c) 2006-2007, Ext JS, LLC.
7699 * Originally Released Under LGPL - original licence link has changed is not relivant.
7702 * <script type="text/javascript">
7705 // Base class for reading structured data from a data source. This class is intended to be
7706 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
7709 * @class Roo.data.DataReader
7710 * Base class for reading structured data from a data source. This class is intended to be
7711 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
7714 Roo.data.DataReader = function(meta, recordType){
7718 this.recordType = recordType instanceof Array ?
7719 Roo.data.Record.create(recordType) : recordType;
7722 Roo.data.DataReader.prototype = {
7724 * Create an empty record
7725 * @param {Object} data (optional) - overlay some values
7726 * @return {Roo.data.Record} record created.
7728 newRow : function(d) {
7730 this.recordType.prototype.fields.each(function(c) {
7732 case 'int' : da[c.name] = 0; break;
7733 case 'date' : da[c.name] = new Date(); break;
7734 case 'float' : da[c.name] = 0.0; break;
7735 case 'boolean' : da[c.name] = false; break;
7736 default : da[c.name] = ""; break;
7740 return new this.recordType(Roo.apply(da, d));
7745 * Ext JS Library 1.1.1
7746 * Copyright(c) 2006-2007, Ext JS, LLC.
7748 * Originally Released Under LGPL - original licence link has changed is not relivant.
7751 * <script type="text/javascript">
7755 * @class Roo.data.DataProxy
7756 * @extends Roo.data.Observable
7757 * This class is an abstract base class for implementations which provide retrieval of
7758 * unformatted data objects.<br>
7760 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
7761 * (of the appropriate type which knows how to parse the data object) to provide a block of
7762 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
7764 * Custom implementations must implement the load method as described in
7765 * {@link Roo.data.HttpProxy#load}.
7767 Roo.data.DataProxy = function(){
7771 * Fires before a network request is made to retrieve a data object.
7772 * @param {Object} This DataProxy object.
7773 * @param {Object} params The params parameter to the load function.
7778 * Fires before the load method's callback is called.
7779 * @param {Object} This DataProxy object.
7780 * @param {Object} o The data object.
7781 * @param {Object} arg The callback argument object passed to the load function.
7785 * @event loadexception
7786 * Fires if an Exception occurs during data retrieval.
7787 * @param {Object} This DataProxy object.
7788 * @param {Object} o The data object.
7789 * @param {Object} arg The callback argument object passed to the load function.
7790 * @param {Object} e The Exception.
7792 loadexception : true
7794 Roo.data.DataProxy.superclass.constructor.call(this);
7797 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7800 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7804 * Ext JS Library 1.1.1
7805 * Copyright(c) 2006-2007, Ext JS, LLC.
7807 * Originally Released Under LGPL - original licence link has changed is not relivant.
7810 * <script type="text/javascript">
7813 * @class Roo.data.MemoryProxy
7814 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7815 * to the Reader when its load method is called.
7817 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7819 Roo.data.MemoryProxy = function(data){
7823 Roo.data.MemoryProxy.superclass.constructor.call(this);
7827 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7829 * Load data from the requested source (in this case an in-memory
7830 * data object passed to the constructor), read the data object into
7831 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7832 * process that block using the passed callback.
7833 * @param {Object} params This parameter is not used by the MemoryProxy class.
7834 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7835 * object into a block of Roo.data.Records.
7836 * @param {Function} callback The function into which to pass the block of Roo.data.records.
7837 * The function must be passed <ul>
7838 * <li>The Record block object</li>
7839 * <li>The "arg" argument from the load function</li>
7840 * <li>A boolean success indicator</li>
7842 * @param {Object} scope The scope in which to call the callback
7843 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7845 load : function(params, reader, callback, scope, arg){
7846 params = params || {};
7849 result = reader.readRecords(this.data);
7851 this.fireEvent("loadexception", this, arg, null, e);
7852 callback.call(scope, null, arg, false);
7855 callback.call(scope, result, arg, true);
7859 update : function(params, records){
7864 * Ext JS Library 1.1.1
7865 * Copyright(c) 2006-2007, Ext JS, LLC.
7867 * Originally Released Under LGPL - original licence link has changed is not relivant.
7870 * <script type="text/javascript">
7873 * @class Roo.data.HttpProxy
7874 * @extends Roo.data.DataProxy
7875 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7876 * configured to reference a certain URL.<br><br>
7878 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7879 * from which the running page was served.<br><br>
7881 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7883 * Be aware that to enable the browser to parse an XML document, the server must set
7884 * the Content-Type header in the HTTP response to "text/xml".
7886 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7887 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7888 * will be used to make the request.
7890 Roo.data.HttpProxy = function(conn){
7891 Roo.data.HttpProxy.superclass.constructor.call(this);
7892 // is conn a conn config or a real conn?
7894 this.useAjax = !conn || !conn.events;
7898 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7899 // thse are take from connection...
7902 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7905 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7906 * extra parameters to each request made by this object. (defaults to undefined)
7909 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7910 * to each request made by this object. (defaults to undefined)
7913 * @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)
7916 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7919 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7925 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7929 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7930 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7931 * a finer-grained basis than the DataProxy events.
7933 getConnection : function(){
7934 return this.useAjax ? Roo.Ajax : this.conn;
7938 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7939 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7940 * process that block using the passed callback.
7941 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7942 * for the request to the remote server.
7943 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7944 * object into a block of Roo.data.Records.
7945 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7946 * The function must be passed <ul>
7947 * <li>The Record block object</li>
7948 * <li>The "arg" argument from the load function</li>
7949 * <li>A boolean success indicator</li>
7951 * @param {Object} scope The scope in which to call the callback
7952 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7954 load : function(params, reader, callback, scope, arg){
7955 if(this.fireEvent("beforeload", this, params) !== false){
7957 params : params || {},
7959 callback : callback,
7964 callback : this.loadResponse,
7968 Roo.applyIf(o, this.conn);
7969 if(this.activeRequest){
7970 Roo.Ajax.abort(this.activeRequest);
7972 this.activeRequest = Roo.Ajax.request(o);
7974 this.conn.request(o);
7977 callback.call(scope||this, null, arg, false);
7982 loadResponse : function(o, success, response){
7983 delete this.activeRequest;
7985 this.fireEvent("loadexception", this, o, response);
7986 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7991 result = o.reader.read(response);
7993 this.fireEvent("loadexception", this, o, response, e);
7994 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7998 this.fireEvent("load", this, o, o.request.arg);
7999 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8003 update : function(dataSet){
8008 updateResponse : function(dataSet){
8013 * Ext JS Library 1.1.1
8014 * Copyright(c) 2006-2007, Ext JS, LLC.
8016 * Originally Released Under LGPL - original licence link has changed is not relivant.
8019 * <script type="text/javascript">
8023 * @class Roo.data.ScriptTagProxy
8024 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8025 * other than the originating domain of the running page.<br><br>
8027 * <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
8028 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8030 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8031 * source code that is used as the source inside a <script> tag.<br><br>
8033 * In order for the browser to process the returned data, the server must wrap the data object
8034 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8035 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8036 * depending on whether the callback name was passed:
8039 boolean scriptTag = false;
8040 String cb = request.getParameter("callback");
8043 response.setContentType("text/javascript");
8045 response.setContentType("application/x-json");
8047 Writer out = response.getWriter();
8049 out.write(cb + "(");
8051 out.print(dataBlock.toJsonString());
8058 * @param {Object} config A configuration object.
8060 Roo.data.ScriptTagProxy = function(config){
8061 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8062 Roo.apply(this, config);
8063 this.head = document.getElementsByTagName("head")[0];
8066 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8068 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8070 * @cfg {String} url The URL from which to request the data object.
8073 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8077 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8078 * the server the name of the callback function set up by the load call to process the returned data object.
8079 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8080 * javascript output which calls this named function passing the data object as its only parameter.
8082 callbackParam : "callback",
8084 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8085 * name to the request.
8090 * Load data from the configured URL, read the data object into
8091 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8092 * process that block using the passed callback.
8093 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8094 * for the request to the remote server.
8095 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8096 * object into a block of Roo.data.Records.
8097 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8098 * The function must be passed <ul>
8099 * <li>The Record block object</li>
8100 * <li>The "arg" argument from the load function</li>
8101 * <li>A boolean success indicator</li>
8103 * @param {Object} scope The scope in which to call the callback
8104 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8106 load : function(params, reader, callback, scope, arg){
8107 if(this.fireEvent("beforeload", this, params) !== false){
8109 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8112 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8114 url += "&_dc=" + (new Date().getTime());
8116 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8119 cb : "stcCallback"+transId,
8120 scriptId : "stcScript"+transId,
8124 callback : callback,
8130 window[trans.cb] = function(o){
8131 conn.handleResponse(o, trans);
8134 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8136 if(this.autoAbort !== false){
8140 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8142 var script = document.createElement("script");
8143 script.setAttribute("src", url);
8144 script.setAttribute("type", "text/javascript");
8145 script.setAttribute("id", trans.scriptId);
8146 this.head.appendChild(script);
8150 callback.call(scope||this, null, arg, false);
8155 isLoading : function(){
8156 return this.trans ? true : false;
8160 * Abort the current server request.
8163 if(this.isLoading()){
8164 this.destroyTrans(this.trans);
8169 destroyTrans : function(trans, isLoaded){
8170 this.head.removeChild(document.getElementById(trans.scriptId));
8171 clearTimeout(trans.timeoutId);
8173 window[trans.cb] = undefined;
8175 delete window[trans.cb];
8178 // if hasn't been loaded, wait for load to remove it to prevent script error
8179 window[trans.cb] = function(){
8180 window[trans.cb] = undefined;
8182 delete window[trans.cb];
8189 handleResponse : function(o, trans){
8191 this.destroyTrans(trans, true);
8194 result = trans.reader.readRecords(o);
8196 this.fireEvent("loadexception", this, o, trans.arg, e);
8197 trans.callback.call(trans.scope||window, null, trans.arg, false);
8200 this.fireEvent("load", this, o, trans.arg);
8201 trans.callback.call(trans.scope||window, result, trans.arg, true);
8205 handleFailure : function(trans){
8207 this.destroyTrans(trans, false);
8208 this.fireEvent("loadexception", this, null, trans.arg);
8209 trans.callback.call(trans.scope||window, null, trans.arg, false);
8213 * Ext JS Library 1.1.1
8214 * Copyright(c) 2006-2007, Ext JS, LLC.
8216 * Originally Released Under LGPL - original licence link has changed is not relivant.
8219 * <script type="text/javascript">
8223 * @class Roo.data.JsonReader
8224 * @extends Roo.data.DataReader
8225 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8226 * based on mappings in a provided Roo.data.Record constructor.
8228 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8229 * in the reply previously.
8234 var RecordDef = Roo.data.Record.create([
8235 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8236 {name: 'occupation'} // This field will use "occupation" as the mapping.
8238 var myReader = new Roo.data.JsonReader({
8239 totalProperty: "results", // The property which contains the total dataset size (optional)
8240 root: "rows", // The property which contains an Array of row objects
8241 id: "id" // The property within each row object that provides an ID for the record (optional)
8245 * This would consume a JSON file like this:
8247 { 'results': 2, 'rows': [
8248 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8249 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8252 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8253 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8254 * paged from the remote server.
8255 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8256 * @cfg {String} root name of the property which contains the Array of row objects.
8257 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8259 * Create a new JsonReader
8260 * @param {Object} meta Metadata configuration options
8261 * @param {Object} recordType Either an Array of field definition objects,
8262 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8264 Roo.data.JsonReader = function(meta, recordType){
8267 // set some defaults:
8269 totalProperty: 'total',
8270 successProperty : 'success',
8275 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8277 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8280 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8281 * Used by Store query builder to append _requestMeta to params.
8284 metaFromRemote : false,
8286 * This method is only used by a DataProxy which has retrieved data from a remote server.
8287 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8288 * @return {Object} data A data block which is used by an Roo.data.Store object as
8289 * a cache of Roo.data.Records.
8291 read : function(response){
8292 var json = response.responseText;
8294 var o = /* eval:var:o */ eval("("+json+")");
8296 throw {message: "JsonReader.read: Json object not found"};
8302 this.metaFromRemote = true;
8303 this.meta = o.metaData;
8304 this.recordType = Roo.data.Record.create(o.metaData.fields);
8305 this.onMetaChange(this.meta, this.recordType, o);
8307 return this.readRecords(o);
8310 // private function a store will implement
8311 onMetaChange : function(meta, recordType, o){
8318 simpleAccess: function(obj, subsc) {
8325 getJsonAccessor: function(){
8327 return function(expr) {
8329 return(re.test(expr))
8330 ? new Function("obj", "return obj." + expr)
8340 * Create a data block containing Roo.data.Records from an XML document.
8341 * @param {Object} o An object which contains an Array of row objects in the property specified
8342 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8343 * which contains the total size of the dataset.
8344 * @return {Object} data A data block which is used by an Roo.data.Store object as
8345 * a cache of Roo.data.Records.
8347 readRecords : function(o){
8349 * After any data loads, the raw JSON data is available for further custom processing.
8353 var s = this.meta, Record = this.recordType,
8354 f = Record.prototype.fields, fi = f.items, fl = f.length;
8356 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8358 if(s.totalProperty) {
8359 this.getTotal = this.getJsonAccessor(s.totalProperty);
8361 if(s.successProperty) {
8362 this.getSuccess = this.getJsonAccessor(s.successProperty);
8364 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8366 var g = this.getJsonAccessor(s.id);
8367 this.getId = function(rec) {
8369 return (r === undefined || r === "") ? null : r;
8372 this.getId = function(){return null;};
8375 for(var jj = 0; jj < fl; jj++){
8377 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8378 this.ef[jj] = this.getJsonAccessor(map);
8382 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8383 if(s.totalProperty){
8384 var vt = parseInt(this.getTotal(o), 10);
8389 if(s.successProperty){
8390 var vs = this.getSuccess(o);
8391 if(vs === false || vs === 'false'){
8396 for(var i = 0; i < c; i++){
8399 var id = this.getId(n);
8400 for(var j = 0; j < fl; j++){
8402 var v = this.ef[j](n);
8404 Roo.log('missing convert for ' + f.name);
8408 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8410 var record = new Record(values, id);
8412 records[i] = record;
8418 totalRecords : totalRecords
8423 * Ext JS Library 1.1.1
8424 * Copyright(c) 2006-2007, Ext JS, LLC.
8426 * Originally Released Under LGPL - original licence link has changed is not relivant.
8429 * <script type="text/javascript">
8433 * @class Roo.data.ArrayReader
8434 * @extends Roo.data.DataReader
8435 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8436 * Each element of that Array represents a row of data fields. The
8437 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8438 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8442 var RecordDef = Roo.data.Record.create([
8443 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8444 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8446 var myReader = new Roo.data.ArrayReader({
8447 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8451 * This would consume an Array like this:
8453 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8455 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8457 * Create a new JsonReader
8458 * @param {Object} meta Metadata configuration options.
8459 * @param {Object} recordType Either an Array of field definition objects
8460 * as specified to {@link Roo.data.Record#create},
8461 * or an {@link Roo.data.Record} object
8462 * created using {@link Roo.data.Record#create}.
8464 Roo.data.ArrayReader = function(meta, recordType){
8465 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8468 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8470 * Create a data block containing Roo.data.Records from an XML document.
8471 * @param {Object} o An Array of row objects which represents the dataset.
8472 * @return {Object} data A data block which is used by an Roo.data.Store object as
8473 * a cache of Roo.data.Records.
8475 readRecords : function(o){
8476 var sid = this.meta ? this.meta.id : null;
8477 var recordType = this.recordType, fields = recordType.prototype.fields;
8480 for(var i = 0; i < root.length; i++){
8483 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8484 for(var j = 0, jlen = fields.length; j < jlen; j++){
8485 var f = fields.items[j];
8486 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8487 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8491 var record = new recordType(values, id);
8493 records[records.length] = record;
8497 totalRecords : records.length
8506 * @class Roo.bootstrap.ComboBox
8507 * @extends Roo.bootstrap.TriggerField
8508 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8509 * @cfg {Boolean} append (true|false) default false
8511 * Create a new ComboBox.
8512 * @param {Object} config Configuration options
8514 Roo.bootstrap.ComboBox = function(config){
8515 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8519 * Fires when the dropdown list is expanded
8520 * @param {Roo.bootstrap.ComboBox} combo This combo box
8525 * Fires when the dropdown list is collapsed
8526 * @param {Roo.bootstrap.ComboBox} combo This combo box
8530 * @event beforeselect
8531 * Fires before a list item is selected. Return false to cancel the selection.
8532 * @param {Roo.bootstrap.ComboBox} combo This combo box
8533 * @param {Roo.data.Record} record The data record returned from the underlying store
8534 * @param {Number} index The index of the selected item in the dropdown list
8536 'beforeselect' : true,
8539 * Fires when a list item is selected
8540 * @param {Roo.bootstrap.ComboBox} combo This combo box
8541 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8542 * @param {Number} index The index of the selected item in the dropdown list
8546 * @event beforequery
8547 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8548 * The event object passed has these properties:
8549 * @param {Roo.bootstrap.ComboBox} combo This combo box
8550 * @param {String} query The query
8551 * @param {Boolean} forceAll true to force "all" query
8552 * @param {Boolean} cancel true to cancel the query
8553 * @param {Object} e The query event object
8555 'beforequery': true,
8558 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8559 * @param {Roo.bootstrap.ComboBox} combo This combo box
8564 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
8565 * @param {Roo.bootstrap.ComboBox} combo This combo box
8566 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
8571 * Fires when the remove value from the combobox array
8572 * @param {Roo.bootstrap.ComboBox} combo This combo box
8579 this.selectedIndex = -1;
8580 if(this.mode == 'local'){
8581 if(config.queryDelay === undefined){
8582 this.queryDelay = 10;
8584 if(config.minChars === undefined){
8590 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
8593 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
8594 * rendering into an Roo.Editor, defaults to false)
8597 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
8598 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
8601 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
8604 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
8605 * the dropdown list (defaults to undefined, with no header element)
8609 * @cfg {String/Roo.Template} tpl The template to use to render the output
8613 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
8615 listWidth: undefined,
8617 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
8618 * mode = 'remote' or 'text' if mode = 'local')
8620 displayField: undefined,
8622 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
8623 * mode = 'remote' or 'value' if mode = 'local').
8624 * Note: use of a valueField requires the user make a selection
8625 * in order for a value to be mapped.
8627 valueField: undefined,
8631 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
8632 * field's data value (defaults to the underlying DOM element's name)
8634 hiddenName: undefined,
8636 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
8640 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
8642 selectedClass: 'active',
8645 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
8649 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
8650 * anchor positions (defaults to 'tl-bl')
8652 listAlign: 'tl-bl?',
8654 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
8658 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
8659 * query specified by the allQuery config option (defaults to 'query')
8661 triggerAction: 'query',
8663 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
8664 * (defaults to 4, does not apply if editable = false)
8668 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
8669 * delay (typeAheadDelay) if it matches a known value (defaults to false)
8673 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
8674 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
8678 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
8679 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
8683 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
8684 * when editable = true (defaults to false)
8686 selectOnFocus:false,
8688 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
8690 queryParam: 'query',
8692 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
8693 * when mode = 'remote' (defaults to 'Loading...')
8695 loadingText: 'Loading...',
8697 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
8701 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
8705 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
8706 * traditional select (defaults to true)
8710 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
8714 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
8718 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
8719 * listWidth has a higher value)
8723 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
8724 * allow the user to set arbitrary text into the field (defaults to false)
8726 forceSelection:false,
8728 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
8729 * if typeAhead = true (defaults to 250)
8731 typeAheadDelay : 250,
8733 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
8734 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
8736 valueNotFoundText : undefined,
8738 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8743 * @cfg {Boolean} disableClear Disable showing of clear button.
8745 disableClear : false,
8747 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8749 alwaysQuery : false,
8752 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
8766 // element that contains real text value.. (when hidden is used..)
8769 initEvents: function(){
8772 throw "can not find store for combo";
8774 this.store = Roo.factory(this.store, Roo.data);
8778 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
8781 if(this.hiddenName){
8783 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
8785 this.hiddenField.dom.value =
8786 this.hiddenValue !== undefined ? this.hiddenValue :
8787 this.value !== undefined ? this.value : '';
8789 // prevent input submission
8790 this.el.dom.removeAttribute('name');
8791 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8796 // this.el.dom.setAttribute('autocomplete', 'off');
8799 var cls = 'x-combo-list';
8800 this.list = this.el.select('ul.dropdown-menu',true).first();
8802 //this.list = new Roo.Layer({
8803 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8806 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8807 this.list.setWidth(lw);
8809 this.list.on('mouseover', this.onViewOver, this);
8810 this.list.on('mousemove', this.onViewMove, this);
8812 this.list.on('scroll', this.onViewScroll, this);
8815 this.list.swallowEvent('mousewheel');
8816 this.assetHeight = 0;
8819 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8820 this.assetHeight += this.header.getHeight();
8823 this.innerList = this.list.createChild({cls:cls+'-inner'});
8824 this.innerList.on('mouseover', this.onViewOver, this);
8825 this.innerList.on('mousemove', this.onViewMove, this);
8826 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8828 if(this.allowBlank && !this.pageSize && !this.disableClear){
8829 this.footer = this.list.createChild({cls:cls+'-ft'});
8830 this.pageTb = new Roo.Toolbar(this.footer);
8834 this.footer = this.list.createChild({cls:cls+'-ft'});
8835 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
8836 {pageSize: this.pageSize});
8840 if (this.pageTb && this.allowBlank && !this.disableClear) {
8842 this.pageTb.add(new Roo.Toolbar.Fill(), {
8843 cls: 'x-btn-icon x-btn-clear',
8849 _this.onSelect(false, -1);
8854 this.assetHeight += this.footer.getHeight();
8859 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8862 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8863 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8865 //this.view.wrapEl.setDisplayed(false);
8866 this.view.on('click', this.onViewClick, this);
8870 this.store.on('beforeload', this.onBeforeLoad, this);
8871 this.store.on('load', this.onLoad, this);
8872 this.store.on('loadexception', this.onLoadException, this);
8875 this.resizer = new Roo.Resizable(this.list, {
8876 pinned:true, handles:'se'
8878 this.resizer.on('resize', function(r, w, h){
8879 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8881 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8882 this.restrictHeight();
8884 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8888 this.editable = true;
8889 this.setEditable(false);
8894 if (typeof(this.events.add.listeners) != 'undefined') {
8896 this.addicon = this.wrap.createChild(
8897 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8899 this.addicon.on('click', function(e) {
8900 this.fireEvent('add', this);
8903 if (typeof(this.events.edit.listeners) != 'undefined') {
8905 this.editicon = this.wrap.createChild(
8906 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8908 this.editicon.setStyle('margin-left', '40px');
8910 this.editicon.on('click', function(e) {
8912 // we fire even if inothing is selected..
8913 this.fireEvent('edit', this, this.lastData );
8919 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8921 this.inKeyMode = true;
8925 "down" : function(e){
8926 if(!this.isExpanded()){
8927 this.onTriggerClick();
8929 this.inKeyMode = true;
8934 "enter" : function(e){
8939 "esc" : function(e){
8943 "tab" : function(e){
8946 if(this.fireEvent("specialkey", this, e)){
8947 this.onViewClick(false);
8955 doRelay : function(foo, bar, hname){
8956 if(hname == 'down' || this.scope.isExpanded()){
8957 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8966 this.queryDelay = Math.max(this.queryDelay || 10,
8967 this.mode == 'local' ? 10 : 250);
8970 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8973 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8975 if(this.editable !== false){
8976 this.inputEl().on("keyup", this.onKeyUp, this);
8978 if(this.forceSelection){
8979 this.on('blur', this.doForce, this);
8983 this.choices = this.el.select('ul.select2-choices', true).first();
8984 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8988 onDestroy : function(){
8990 this.view.setStore(null);
8991 this.view.el.removeAllListeners();
8992 this.view.el.remove();
8993 this.view.purgeListeners();
8996 this.list.dom.innerHTML = '';
8999 this.store.un('beforeload', this.onBeforeLoad, this);
9000 this.store.un('load', this.onLoad, this);
9001 this.store.un('loadexception', this.onLoadException, this);
9003 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9007 fireKey : function(e){
9008 if(e.isNavKeyPress() && !this.list.isVisible()){
9009 this.fireEvent("specialkey", this, e);
9014 onResize: function(w, h){
9015 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9017 // if(typeof w != 'number'){
9018 // // we do not handle it!?!?
9021 // var tw = this.trigger.getWidth();
9022 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9023 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9025 // this.inputEl().setWidth( this.adjustWidth('input', x));
9027 // //this.trigger.setStyle('left', x+'px');
9029 // if(this.list && this.listWidth === undefined){
9030 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9031 // this.list.setWidth(lw);
9032 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9040 * Allow or prevent the user from directly editing the field text. If false is passed,
9041 * the user will only be able to select from the items defined in the dropdown list. This method
9042 * is the runtime equivalent of setting the 'editable' config option at config time.
9043 * @param {Boolean} value True to allow the user to directly edit the field text
9045 setEditable : function(value){
9046 if(value == this.editable){
9049 this.editable = value;
9051 this.inputEl().dom.setAttribute('readOnly', true);
9052 this.inputEl().on('mousedown', this.onTriggerClick, this);
9053 this.inputEl().addClass('x-combo-noedit');
9055 this.inputEl().dom.setAttribute('readOnly', false);
9056 this.inputEl().un('mousedown', this.onTriggerClick, this);
9057 this.inputEl().removeClass('x-combo-noedit');
9063 onBeforeLoad : function(combo,opts){
9068 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9070 this.restrictHeight();
9071 this.selectedIndex = -1;
9075 onLoad : function(){
9077 this.hasQuery = false;
9083 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9084 this.loading.hide();
9087 if(this.store.getCount() > 0){
9089 this.restrictHeight();
9090 if(this.lastQuery == this.allQuery){
9092 this.inputEl().dom.select();
9094 if(!this.selectByValue(this.value, true)){
9095 this.select(0, true);
9099 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9100 this.taTask.delay(this.typeAheadDelay);
9104 this.onEmptyResults();
9110 onLoadException : function()
9112 this.hasQuery = false;
9114 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9115 this.loading.hide();
9119 Roo.log(this.store.reader.jsonData);
9120 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9122 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9128 onTypeAhead : function(){
9129 if(this.store.getCount() > 0){
9130 var r = this.store.getAt(0);
9131 var newValue = r.data[this.displayField];
9132 var len = newValue.length;
9133 var selStart = this.getRawValue().length;
9135 if(selStart != len){
9136 this.setRawValue(newValue);
9137 this.selectText(selStart, newValue.length);
9143 onSelect : function(record, index){
9145 if(this.fireEvent('beforeselect', this, record, index) !== false){
9147 this.setFromData(index > -1 ? record.data : false);
9150 this.fireEvent('select', this, record, index);
9155 * Returns the currently selected field value or empty string if no value is set.
9156 * @return {String} value The selected value
9158 getValue : function(){
9161 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9164 if(this.valueField){
9165 return typeof this.value != 'undefined' ? this.value : '';
9167 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9172 * Clears any text/value currently set in the field
9174 clearValue : function(){
9175 if(this.hiddenField){
9176 this.hiddenField.dom.value = '';
9179 this.setRawValue('');
9180 this.lastSelectionText = '';
9185 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9186 * will be displayed in the field. If the value does not match the data value of an existing item,
9187 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9188 * Otherwise the field will be blank (although the value will still be set).
9189 * @param {String} value The value to match
9191 setValue : function(v){
9198 if(this.valueField){
9199 var r = this.findRecord(this.valueField, v);
9201 text = r.data[this.displayField];
9202 }else if(this.valueNotFoundText !== undefined){
9203 text = this.valueNotFoundText;
9206 this.lastSelectionText = text;
9207 if(this.hiddenField){
9208 this.hiddenField.dom.value = v;
9210 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9214 * @property {Object} the last set data for the element
9219 * Sets the value of the field based on a object which is related to the record format for the store.
9220 * @param {Object} value the value to set as. or false on reset?
9222 setFromData : function(o){
9229 var dv = ''; // display value
9230 var vv = ''; // value value..
9232 if (this.displayField) {
9233 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9235 // this is an error condition!!!
9236 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9239 if(this.valueField){
9240 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9243 if(this.hiddenField){
9244 this.hiddenField.dom.value = vv;
9246 this.lastSelectionText = dv;
9247 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9251 // no hidden field.. - we store the value in 'value', but still display
9252 // display field!!!!
9253 this.lastSelectionText = dv;
9254 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9261 // overridden so that last data is reset..
9262 this.setValue(this.originalValue);
9263 this.clearInvalid();
9264 this.lastData = false;
9266 this.view.clearSelections();
9270 findRecord : function(prop, value){
9272 if(this.store.getCount() > 0){
9273 this.store.each(function(r){
9274 if(r.data[prop] == value){
9286 // returns hidden if it's set..
9287 if (!this.rendered) {return ''};
9288 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9292 onViewMove : function(e, t){
9293 this.inKeyMode = false;
9297 onViewOver : function(e, t){
9298 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9301 var item = this.view.findItemFromChild(t);
9303 var index = this.view.indexOf(item);
9304 this.select(index, false);
9309 onViewClick : function(doFocus)
9311 var index = this.view.getSelectedIndexes()[0];
9312 var r = this.store.getAt(index);
9314 this.onSelect(r, index);
9316 if(doFocus !== false && !this.blockFocus){
9317 this.inputEl().focus();
9322 restrictHeight : function(){
9323 //this.innerList.dom.style.height = '';
9324 //var inner = this.innerList.dom;
9325 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9326 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9327 //this.list.beginUpdate();
9328 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9329 this.list.alignTo(this.inputEl(), this.listAlign);
9330 //this.list.endUpdate();
9334 onEmptyResults : function(){
9339 * Returns true if the dropdown list is expanded, else false.
9341 isExpanded : function(){
9342 return this.list.isVisible();
9346 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9347 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9348 * @param {String} value The data value of the item to select
9349 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9350 * selected item if it is not currently in view (defaults to true)
9351 * @return {Boolean} True if the value matched an item in the list, else false
9353 selectByValue : function(v, scrollIntoView){
9354 if(v !== undefined && v !== null){
9355 var r = this.findRecord(this.valueField || this.displayField, v);
9357 this.select(this.store.indexOf(r), scrollIntoView);
9365 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9366 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9367 * @param {Number} index The zero-based index of the list item to select
9368 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9369 * selected item if it is not currently in view (defaults to true)
9371 select : function(index, scrollIntoView){
9372 this.selectedIndex = index;
9373 this.view.select(index);
9374 if(scrollIntoView !== false){
9375 var el = this.view.getNode(index);
9377 //this.innerList.scrollChildIntoView(el, false);
9384 selectNext : function(){
9385 var ct = this.store.getCount();
9387 if(this.selectedIndex == -1){
9389 }else if(this.selectedIndex < ct-1){
9390 this.select(this.selectedIndex+1);
9396 selectPrev : function(){
9397 var ct = this.store.getCount();
9399 if(this.selectedIndex == -1){
9401 }else if(this.selectedIndex != 0){
9402 this.select(this.selectedIndex-1);
9408 onKeyUp : function(e){
9409 if(this.editable !== false && !e.isSpecialKey()){
9410 this.lastKey = e.getKey();
9411 this.dqTask.delay(this.queryDelay);
9416 validateBlur : function(){
9417 return !this.list || !this.list.isVisible();
9421 initQuery : function(){
9422 this.doQuery(this.getRawValue());
9426 doForce : function(){
9427 if(this.el.dom.value.length > 0){
9429 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9435 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9436 * query allowing the query action to be canceled if needed.
9437 * @param {String} query The SQL query to execute
9438 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9439 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9440 * saved in the current store (defaults to false)
9442 doQuery : function(q, forceAll){
9444 if(q === undefined || q === null){
9453 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9458 forceAll = qe.forceAll;
9459 if(forceAll === true || (q.length >= this.minChars)){
9461 this.hasQuery = true;
9463 if(this.lastQuery != q || this.alwaysQuery){
9465 if(this.mode == 'local'){
9466 this.selectedIndex = -1;
9468 this.store.clearFilter();
9470 this.store.filter(this.displayField, q);
9474 this.store.baseParams[this.queryParam] = q;
9476 var options = {params : this.getParams(q)};
9480 options.params.start = this.page * this.pageSize;
9483 this.store.load(options);
9487 this.selectedIndex = -1;
9492 this.loadNext = false;
9496 getParams : function(q){
9498 //p[this.queryParam] = q;
9502 p.limit = this.pageSize;
9508 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9510 collapse : function(){
9511 if(!this.isExpanded()){
9516 Roo.get(document).un('mousedown', this.collapseIf, this);
9517 Roo.get(document).un('mousewheel', this.collapseIf, this);
9518 if (!this.editable) {
9519 Roo.get(document).un('keydown', this.listKeyPress, this);
9521 this.fireEvent('collapse', this);
9525 collapseIf : function(e){
9526 var in_combo = e.within(this.el);
9527 var in_list = e.within(this.list);
9529 if (in_combo || in_list) {
9530 //e.stopPropagation();
9539 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9541 expand : function(){
9543 if(this.isExpanded() || !this.hasFocus){
9547 this.list.alignTo(this.inputEl(), this.listAlign);
9549 Roo.get(document).on('mousedown', this.collapseIf, this);
9550 Roo.get(document).on('mousewheel', this.collapseIf, this);
9551 if (!this.editable) {
9552 Roo.get(document).on('keydown', this.listKeyPress, this);
9555 this.fireEvent('expand', this);
9559 // Implements the default empty TriggerField.onTriggerClick function
9560 onTriggerClick : function()
9562 Roo.log('trigger click');
9569 this.loadNext = false;
9571 if(this.isExpanded()){
9573 if (!this.blockFocus) {
9574 this.inputEl().focus();
9578 this.hasFocus = true;
9579 if(this.triggerAction == 'all') {
9580 this.doQuery(this.allQuery, true);
9582 this.doQuery(this.getRawValue());
9584 if (!this.blockFocus) {
9585 this.inputEl().focus();
9589 listKeyPress : function(e)
9591 //Roo.log('listkeypress');
9592 // scroll to first matching element based on key pres..
9593 if (e.isSpecialKey()) {
9596 var k = String.fromCharCode(e.getKey()).toUpperCase();
9599 var csel = this.view.getSelectedNodes();
9600 var cselitem = false;
9602 var ix = this.view.indexOf(csel[0]);
9603 cselitem = this.store.getAt(ix);
9604 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
9610 this.store.each(function(v) {
9612 // start at existing selection.
9613 if (cselitem.id == v.id) {
9619 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
9620 match = this.store.indexOf(v);
9626 if (match === false) {
9627 return true; // no more action?
9630 this.view.select(match);
9631 var sn = Roo.get(this.view.getSelectedNodes()[0])
9632 //sn.scrollIntoView(sn.dom.parentNode, false);
9635 onViewScroll : function(e, t){
9637 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
9641 this.hasQuery = true;
9643 this.loading = this.list.select('.loading', true).first();
9645 if(this.loading === null){
9646 this.list.createChild({
9648 cls: 'loading select2-more-results select2-active',
9649 html: 'Loading more results...'
9652 this.loading = this.list.select('.loading', true).first();
9654 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
9656 this.loading.hide();
9659 this.loading.show();
9664 this.loadNext = true;
9666 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
9671 addItem : function(o)
9673 var dv = ''; // display value
9675 if (this.displayField) {
9676 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9678 // this is an error condition!!!
9679 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9686 var choice = this.choices.createChild({
9688 cls: 'select2-search-choice',
9697 cls: 'select2-search-choice-close',
9702 }, this.searchField);
9704 var close = choice.select('a.select2-search-choice-close', true).first()
9706 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
9713 this.inputEl().dom.value = '';
9717 onRemoveItem : function(e, _self, o)
9719 Roo.log('remove item');
9720 var index = this.item.indexOf(o.data) * 1;
9723 Roo.log('not this item?!');
9727 this.item.splice(index, 1);
9732 this.fireEvent('remove', this);
9736 syncValue : function()
9738 if(!this.item.length){
9745 Roo.each(this.item, function(i){
9746 if(_this.valueField){
9747 value.push(i[_this.valueField]);
9754 this.value = value.join(',');
9756 if(this.hiddenField){
9757 this.hiddenField.dom.value = this.value;
9761 clearItem : function()
9769 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
9779 * @cfg {Boolean} grow
9783 * @cfg {Number} growMin
9787 * @cfg {Number} growMax
9797 * Ext JS Library 1.1.1
9798 * Copyright(c) 2006-2007, Ext JS, LLC.
9800 * Originally Released Under LGPL - original licence link has changed is not relivant.
9803 * <script type="text/javascript">
9808 * @extends Roo.util.Observable
9809 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9810 * This class also supports single and multi selection modes. <br>
9811 * Create a data model bound view:
9813 var store = new Roo.data.Store(...);
9815 var view = new Roo.View({
9817 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9820 selectedClass: "ydataview-selected",
9824 // listen for node click?
9825 view.on("click", function(vw, index, node, e){
9826 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9830 dataModel.load("foobar.xml");
9832 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9834 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9835 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9837 * Note: old style constructor is still suported (container, template, config)
9841 * @param {Object} config The config object
9844 Roo.View = function(config, depreciated_tpl, depreciated_config){
9846 if (typeof(depreciated_tpl) == 'undefined') {
9847 // new way.. - universal constructor.
9848 Roo.apply(this, config);
9849 this.el = Roo.get(this.el);
9852 this.el = Roo.get(config);
9853 this.tpl = depreciated_tpl;
9854 Roo.apply(this, depreciated_config);
9856 this.wrapEl = this.el.wrap().wrap();
9857 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9860 if(typeof(this.tpl) == "string"){
9861 this.tpl = new Roo.Template(this.tpl);
9863 // support xtype ctors..
9864 this.tpl = new Roo.factory(this.tpl, Roo);
9876 * @event beforeclick
9877 * Fires before a click is processed. Returns false to cancel the default action.
9878 * @param {Roo.View} this
9879 * @param {Number} index The index of the target node
9880 * @param {HTMLElement} node The target node
9881 * @param {Roo.EventObject} e The raw event object
9883 "beforeclick" : true,
9886 * Fires when a template node is clicked.
9887 * @param {Roo.View} this
9888 * @param {Number} index The index of the target node
9889 * @param {HTMLElement} node The target node
9890 * @param {Roo.EventObject} e The raw event object
9895 * Fires when a template node is double clicked.
9896 * @param {Roo.View} this
9897 * @param {Number} index The index of the target node
9898 * @param {HTMLElement} node The target node
9899 * @param {Roo.EventObject} e The raw event object
9903 * @event contextmenu
9904 * Fires when a template node is right clicked.
9905 * @param {Roo.View} this
9906 * @param {Number} index The index of the target node
9907 * @param {HTMLElement} node The target node
9908 * @param {Roo.EventObject} e The raw event object
9910 "contextmenu" : true,
9912 * @event selectionchange
9913 * Fires when the selected nodes change.
9914 * @param {Roo.View} this
9915 * @param {Array} selections Array of the selected nodes
9917 "selectionchange" : true,
9920 * @event beforeselect
9921 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9922 * @param {Roo.View} this
9923 * @param {HTMLElement} node The node to be selected
9924 * @param {Array} selections Array of currently selected nodes
9926 "beforeselect" : true,
9928 * @event preparedata
9929 * Fires on every row to render, to allow you to change the data.
9930 * @param {Roo.View} this
9931 * @param {Object} data to be rendered (change this)
9933 "preparedata" : true
9941 "click": this.onClick,
9942 "dblclick": this.onDblClick,
9943 "contextmenu": this.onContextMenu,
9947 this.selections = [];
9949 this.cmp = new Roo.CompositeElementLite([]);
9951 this.store = Roo.factory(this.store, Roo.data);
9952 this.setStore(this.store, true);
9955 if ( this.footer && this.footer.xtype) {
9957 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9959 this.footer.dataSource = this.store
9960 this.footer.container = fctr;
9961 this.footer = Roo.factory(this.footer, Roo);
9962 fctr.insertFirst(this.el);
9964 // this is a bit insane - as the paging toolbar seems to detach the el..
9965 // dom.parentNode.parentNode.parentNode
9966 // they get detached?
9970 Roo.View.superclass.constructor.call(this);
9975 Roo.extend(Roo.View, Roo.util.Observable, {
9978 * @cfg {Roo.data.Store} store Data store to load data from.
9983 * @cfg {String|Roo.Element} el The container element.
9988 * @cfg {String|Roo.Template} tpl The template used by this View
9992 * @cfg {String} dataName the named area of the template to use as the data area
9993 * Works with domtemplates roo-name="name"
9997 * @cfg {String} selectedClass The css class to add to selected nodes
9999 selectedClass : "x-view-selected",
10001 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10006 * @cfg {String} text to display on mask (default Loading)
10010 * @cfg {Boolean} multiSelect Allow multiple selection
10012 multiSelect : false,
10014 * @cfg {Boolean} singleSelect Allow single selection
10016 singleSelect: false,
10019 * @cfg {Boolean} toggleSelect - selecting
10021 toggleSelect : false,
10024 * Returns the element this view is bound to.
10025 * @return {Roo.Element}
10027 getEl : function(){
10028 return this.wrapEl;
10034 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10036 refresh : function(){
10037 Roo.log('refresh');
10040 // if we are using something like 'domtemplate', then
10041 // the what gets used is:
10042 // t.applySubtemplate(NAME, data, wrapping data..)
10043 // the outer template then get' applied with
10044 // the store 'extra data'
10045 // and the body get's added to the
10046 // roo-name="data" node?
10047 // <span class='roo-tpl-{name}'></span> ?????
10051 this.clearSelections();
10052 this.el.update("");
10054 var records = this.store.getRange();
10055 if(records.length < 1) {
10057 // is this valid?? = should it render a template??
10059 this.el.update(this.emptyText);
10063 if (this.dataName) {
10064 this.el.update(t.apply(this.store.meta)); //????
10065 el = this.el.child('.roo-tpl-' + this.dataName);
10068 for(var i = 0, len = records.length; i < len; i++){
10069 var data = this.prepareData(records[i].data, i, records[i]);
10070 this.fireEvent("preparedata", this, data, i, records[i]);
10071 html[html.length] = Roo.util.Format.trim(
10073 t.applySubtemplate(this.dataName, data, this.store.meta) :
10080 el.update(html.join(""));
10081 this.nodes = el.dom.childNodes;
10082 this.updateIndexes(0);
10087 * Function to override to reformat the data that is sent to
10088 * the template for each node.
10089 * DEPRICATED - use the preparedata event handler.
10090 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10091 * a JSON object for an UpdateManager bound view).
10093 prepareData : function(data, index, record)
10095 this.fireEvent("preparedata", this, data, index, record);
10099 onUpdate : function(ds, record){
10100 Roo.log('on update');
10101 this.clearSelections();
10102 var index = this.store.indexOf(record);
10103 var n = this.nodes[index];
10104 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10105 n.parentNode.removeChild(n);
10106 this.updateIndexes(index, index);
10112 onAdd : function(ds, records, index)
10114 Roo.log(['on Add', ds, records, index] );
10115 this.clearSelections();
10116 if(this.nodes.length == 0){
10120 var n = this.nodes[index];
10121 for(var i = 0, len = records.length; i < len; i++){
10122 var d = this.prepareData(records[i].data, i, records[i]);
10124 this.tpl.insertBefore(n, d);
10127 this.tpl.append(this.el, d);
10130 this.updateIndexes(index);
10133 onRemove : function(ds, record, index){
10134 Roo.log('onRemove');
10135 this.clearSelections();
10136 var el = this.dataName ?
10137 this.el.child('.roo-tpl-' + this.dataName) :
10140 el.dom.removeChild(this.nodes[index]);
10141 this.updateIndexes(index);
10145 * Refresh an individual node.
10146 * @param {Number} index
10148 refreshNode : function(index){
10149 this.onUpdate(this.store, this.store.getAt(index));
10152 updateIndexes : function(startIndex, endIndex){
10153 var ns = this.nodes;
10154 startIndex = startIndex || 0;
10155 endIndex = endIndex || ns.length - 1;
10156 for(var i = startIndex; i <= endIndex; i++){
10157 ns[i].nodeIndex = i;
10162 * Changes the data store this view uses and refresh the view.
10163 * @param {Store} store
10165 setStore : function(store, initial){
10166 if(!initial && this.store){
10167 this.store.un("datachanged", this.refresh);
10168 this.store.un("add", this.onAdd);
10169 this.store.un("remove", this.onRemove);
10170 this.store.un("update", this.onUpdate);
10171 this.store.un("clear", this.refresh);
10172 this.store.un("beforeload", this.onBeforeLoad);
10173 this.store.un("load", this.onLoad);
10174 this.store.un("loadexception", this.onLoad);
10178 store.on("datachanged", this.refresh, this);
10179 store.on("add", this.onAdd, this);
10180 store.on("remove", this.onRemove, this);
10181 store.on("update", this.onUpdate, this);
10182 store.on("clear", this.refresh, this);
10183 store.on("beforeload", this.onBeforeLoad, this);
10184 store.on("load", this.onLoad, this);
10185 store.on("loadexception", this.onLoad, this);
10193 * onbeforeLoad - masks the loading area.
10196 onBeforeLoad : function(store,opts)
10198 Roo.log('onBeforeLoad');
10200 this.el.update("");
10202 this.el.mask(this.mask ? this.mask : "Loading" );
10204 onLoad : function ()
10211 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10212 * @param {HTMLElement} node
10213 * @return {HTMLElement} The template node
10215 findItemFromChild : function(node){
10216 var el = this.dataName ?
10217 this.el.child('.roo-tpl-' + this.dataName,true) :
10220 if(!node || node.parentNode == el){
10223 var p = node.parentNode;
10224 while(p && p != el){
10225 if(p.parentNode == el){
10234 onClick : function(e){
10235 var item = this.findItemFromChild(e.getTarget());
10237 var index = this.indexOf(item);
10238 if(this.onItemClick(item, index, e) !== false){
10239 this.fireEvent("click", this, index, item, e);
10242 this.clearSelections();
10247 onContextMenu : function(e){
10248 var item = this.findItemFromChild(e.getTarget());
10250 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10255 onDblClick : function(e){
10256 var item = this.findItemFromChild(e.getTarget());
10258 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10262 onItemClick : function(item, index, e)
10264 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10267 if (this.toggleSelect) {
10268 var m = this.isSelected(item) ? 'unselect' : 'select';
10271 _t[m](item, true, false);
10274 if(this.multiSelect || this.singleSelect){
10275 if(this.multiSelect && e.shiftKey && this.lastSelection){
10276 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10278 this.select(item, this.multiSelect && e.ctrlKey);
10279 this.lastSelection = item;
10281 e.preventDefault();
10287 * Get the number of selected nodes.
10290 getSelectionCount : function(){
10291 return this.selections.length;
10295 * Get the currently selected nodes.
10296 * @return {Array} An array of HTMLElements
10298 getSelectedNodes : function(){
10299 return this.selections;
10303 * Get the indexes of the selected nodes.
10306 getSelectedIndexes : function(){
10307 var indexes = [], s = this.selections;
10308 for(var i = 0, len = s.length; i < len; i++){
10309 indexes.push(s[i].nodeIndex);
10315 * Clear all selections
10316 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10318 clearSelections : function(suppressEvent){
10319 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10320 this.cmp.elements = this.selections;
10321 this.cmp.removeClass(this.selectedClass);
10322 this.selections = [];
10323 if(!suppressEvent){
10324 this.fireEvent("selectionchange", this, this.selections);
10330 * Returns true if the passed node is selected
10331 * @param {HTMLElement/Number} node The node or node index
10332 * @return {Boolean}
10334 isSelected : function(node){
10335 var s = this.selections;
10339 node = this.getNode(node);
10340 return s.indexOf(node) !== -1;
10345 * @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
10346 * @param {Boolean} keepExisting (optional) true to keep existing selections
10347 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10349 select : function(nodeInfo, keepExisting, suppressEvent){
10350 if(nodeInfo instanceof Array){
10352 this.clearSelections(true);
10354 for(var i = 0, len = nodeInfo.length; i < len; i++){
10355 this.select(nodeInfo[i], true, true);
10359 var node = this.getNode(nodeInfo);
10360 if(!node || this.isSelected(node)){
10361 return; // already selected.
10364 this.clearSelections(true);
10366 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10367 Roo.fly(node).addClass(this.selectedClass);
10368 this.selections.push(node);
10369 if(!suppressEvent){
10370 this.fireEvent("selectionchange", this, this.selections);
10378 * @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
10379 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10380 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10382 unselect : function(nodeInfo, keepExisting, suppressEvent)
10384 if(nodeInfo instanceof Array){
10385 Roo.each(this.selections, function(s) {
10386 this.unselect(s, nodeInfo);
10390 var node = this.getNode(nodeInfo);
10391 if(!node || !this.isSelected(node)){
10392 Roo.log("not selected");
10393 return; // not selected.
10397 Roo.each(this.selections, function(s) {
10399 Roo.fly(node).removeClass(this.selectedClass);
10406 this.selections= ns;
10407 this.fireEvent("selectionchange", this, this.selections);
10411 * Gets a template node.
10412 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10413 * @return {HTMLElement} The node or null if it wasn't found
10415 getNode : function(nodeInfo){
10416 if(typeof nodeInfo == "string"){
10417 return document.getElementById(nodeInfo);
10418 }else if(typeof nodeInfo == "number"){
10419 return this.nodes[nodeInfo];
10425 * Gets a range template nodes.
10426 * @param {Number} startIndex
10427 * @param {Number} endIndex
10428 * @return {Array} An array of nodes
10430 getNodes : function(start, end){
10431 var ns = this.nodes;
10432 start = start || 0;
10433 end = typeof end == "undefined" ? ns.length - 1 : end;
10436 for(var i = start; i <= end; i++){
10440 for(var i = start; i >= end; i--){
10448 * Finds the index of the passed node
10449 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10450 * @return {Number} The index of the node or -1
10452 indexOf : function(node){
10453 node = this.getNode(node);
10454 if(typeof node.nodeIndex == "number"){
10455 return node.nodeIndex;
10457 var ns = this.nodes;
10458 for(var i = 0, len = ns.length; i < len; i++){
10469 * based on jquery fullcalendar
10473 Roo.bootstrap = Roo.bootstrap || {};
10475 * @class Roo.bootstrap.Calendar
10476 * @extends Roo.bootstrap.Component
10477 * Bootstrap Calendar class
10478 * @cfg {Boolean} loadMask (true|false) default false
10479 * @cfg {Object} header generate the user specific header of the calendar, default false
10482 * Create a new Container
10483 * @param {Object} config The config object
10488 Roo.bootstrap.Calendar = function(config){
10489 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10493 * Fires when a date is selected
10494 * @param {DatePicker} this
10495 * @param {Date} date The selected date
10499 * @event monthchange
10500 * Fires when the displayed month changes
10501 * @param {DatePicker} this
10502 * @param {Date} date The selected month
10504 'monthchange': true,
10506 * @event evententer
10507 * Fires when mouse over an event
10508 * @param {Calendar} this
10509 * @param {event} Event
10511 'evententer': true,
10513 * @event eventleave
10514 * Fires when the mouse leaves an
10515 * @param {Calendar} this
10518 'eventleave': true,
10520 * @event eventclick
10521 * Fires when the mouse click an
10522 * @param {Calendar} this
10531 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10534 * @cfg {Number} startDay
10535 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10543 getAutoCreate : function(){
10546 var fc_button = function(name, corner, style, content ) {
10547 return Roo.apply({},{
10549 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10551 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10554 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
10565 style : 'width:100%',
10572 cls : 'fc-header-left',
10574 fc_button('prev', 'left', 'arrow', '‹' ),
10575 fc_button('next', 'right', 'arrow', '›' ),
10576 { tag: 'span', cls: 'fc-header-space' },
10577 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
10585 cls : 'fc-header-center',
10589 cls: 'fc-header-title',
10592 html : 'month / year'
10600 cls : 'fc-header-right',
10602 /* fc_button('month', 'left', '', 'month' ),
10603 fc_button('week', '', '', 'week' ),
10604 fc_button('day', 'right', '', 'day' )
10616 header = this.header;
10619 var cal_heads = function() {
10621 // fixme - handle this.
10623 for (var i =0; i < Date.dayNames.length; i++) {
10624 var d = Date.dayNames[i];
10627 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
10628 html : d.substring(0,3)
10632 ret[0].cls += ' fc-first';
10633 ret[6].cls += ' fc-last';
10636 var cal_cell = function(n) {
10639 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10644 cls: 'fc-day-number',
10648 cls: 'fc-day-content',
10652 style: 'position: relative;' // height: 17px;
10664 var cal_rows = function() {
10667 for (var r = 0; r < 6; r++) {
10674 for (var i =0; i < Date.dayNames.length; i++) {
10675 var d = Date.dayNames[i];
10676 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10679 row.cn[0].cls+=' fc-first';
10680 row.cn[0].cn[0].style = 'min-height:90px';
10681 row.cn[6].cls+=' fc-last';
10685 ret[0].cls += ' fc-first';
10686 ret[4].cls += ' fc-prev-last';
10687 ret[5].cls += ' fc-last';
10694 cls: 'fc-border-separate',
10695 style : 'width:100%',
10703 cls : 'fc-first fc-last',
10721 cls : 'fc-content',
10722 style : "position: relative;",
10725 cls : 'fc-view fc-view-month fc-grid',
10726 style : 'position: relative',
10727 unselectable : 'on',
10730 cls : 'fc-event-container',
10731 style : 'position:absolute;z-index:8;top:0;left:0;'
10749 initEvents : function()
10752 throw "can not find store for calendar";
10758 style: "text-align:center",
10762 style: "background-color:white;width:50%;margin:250 auto",
10766 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10777 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10779 var size = this.el.select('.fc-content', true).first().getSize();
10780 this.maskEl.setSize(size.width, size.height);
10781 this.maskEl.enableDisplayMode("block");
10782 if(!this.loadMask){
10783 this.maskEl.hide();
10786 this.store = Roo.factory(this.store, Roo.data);
10787 this.store.on('load', this.onLoad, this);
10788 this.store.on('beforeload', this.onBeforeLoad, this);
10792 this.cells = this.el.select('.fc-day',true);
10793 //Roo.log(this.cells);
10794 this.textNodes = this.el.query('.fc-day-number');
10795 this.cells.addClassOnOver('fc-state-hover');
10797 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10798 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10799 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10800 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10802 this.on('monthchange', this.onMonthChange, this);
10804 this.update(new Date().clearTime());
10807 resize : function() {
10808 var sz = this.el.getSize();
10810 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10811 this.el.select('.fc-day-content div',true).setHeight(34);
10816 showPrevMonth : function(e){
10817 this.update(this.activeDate.add("mo", -1));
10819 showToday : function(e){
10820 this.update(new Date().clearTime());
10823 showNextMonth : function(e){
10824 this.update(this.activeDate.add("mo", 1));
10828 showPrevYear : function(){
10829 this.update(this.activeDate.add("y", -1));
10833 showNextYear : function(){
10834 this.update(this.activeDate.add("y", 1));
10839 update : function(date)
10841 var vd = this.activeDate;
10842 this.activeDate = date;
10843 // if(vd && this.el){
10844 // var t = date.getTime();
10845 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10846 // Roo.log('using add remove');
10848 // this.fireEvent('monthchange', this, date);
10850 // this.cells.removeClass("fc-state-highlight");
10851 // this.cells.each(function(c){
10852 // if(c.dateValue == t){
10853 // c.addClass("fc-state-highlight");
10854 // setTimeout(function(){
10855 // try{c.dom.firstChild.focus();}catch(e){}
10865 var days = date.getDaysInMonth();
10867 var firstOfMonth = date.getFirstDateOfMonth();
10868 var startingPos = firstOfMonth.getDay()-this.startDay;
10870 if(startingPos < this.startDay){
10874 var pm = date.add(Date.MONTH, -1);
10875 var prevStart = pm.getDaysInMonth()-startingPos;
10877 this.cells = this.el.select('.fc-day',true);
10878 this.textNodes = this.el.query('.fc-day-number');
10879 this.cells.addClassOnOver('fc-state-hover');
10881 var cells = this.cells.elements;
10882 var textEls = this.textNodes;
10884 Roo.each(cells, function(cell){
10885 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10888 days += startingPos;
10890 // convert everything to numbers so it's fast
10891 var day = 86400000;
10892 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10895 //Roo.log(prevStart);
10897 var today = new Date().clearTime().getTime();
10898 var sel = date.clearTime().getTime();
10899 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10900 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10901 var ddMatch = this.disabledDatesRE;
10902 var ddText = this.disabledDatesText;
10903 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10904 var ddaysText = this.disabledDaysText;
10905 var format = this.format;
10907 var setCellClass = function(cal, cell){
10909 //Roo.log('set Cell Class');
10911 var t = d.getTime();
10915 cell.dateValue = t;
10917 cell.className += " fc-today";
10918 cell.className += " fc-state-highlight";
10919 cell.title = cal.todayText;
10922 // disable highlight in other month..
10923 //cell.className += " fc-state-highlight";
10928 cell.className = " fc-state-disabled";
10929 cell.title = cal.minText;
10933 cell.className = " fc-state-disabled";
10934 cell.title = cal.maxText;
10938 if(ddays.indexOf(d.getDay()) != -1){
10939 cell.title = ddaysText;
10940 cell.className = " fc-state-disabled";
10943 if(ddMatch && format){
10944 var fvalue = d.dateFormat(format);
10945 if(ddMatch.test(fvalue)){
10946 cell.title = ddText.replace("%0", fvalue);
10947 cell.className = " fc-state-disabled";
10951 if (!cell.initialClassName) {
10952 cell.initialClassName = cell.dom.className;
10955 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10960 for(; i < startingPos; i++) {
10961 textEls[i].innerHTML = (++prevStart);
10962 d.setDate(d.getDate()+1);
10964 cells[i].className = "fc-past fc-other-month";
10965 setCellClass(this, cells[i]);
10970 for(; i < days; i++){
10971 intDay = i - startingPos + 1;
10972 textEls[i].innerHTML = (intDay);
10973 d.setDate(d.getDate()+1);
10975 cells[i].className = ''; // "x-date-active";
10976 setCellClass(this, cells[i]);
10980 for(; i < 42; i++) {
10981 textEls[i].innerHTML = (++extraDays);
10982 d.setDate(d.getDate()+1);
10984 cells[i].className = "fc-future fc-other-month";
10985 setCellClass(this, cells[i]);
10988 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10990 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10992 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10993 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10995 if(totalRows != 6){
10996 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10997 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11000 this.fireEvent('monthchange', this, date);
11004 if(!this.internalRender){
11005 var main = this.el.dom.firstChild;
11006 var w = main.offsetWidth;
11007 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11008 Roo.fly(main).setWidth(w);
11009 this.internalRender = true;
11010 // opera does not respect the auto grow header center column
11011 // then, after it gets a width opera refuses to recalculate
11012 // without a second pass
11013 if(Roo.isOpera && !this.secondPass){
11014 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11015 this.secondPass = true;
11016 this.update.defer(10, this, [date]);
11023 findCell : function(dt) {
11024 dt = dt.clearTime().getTime();
11026 this.cells.each(function(c){
11027 //Roo.log("check " +c.dateValue + '?=' + dt);
11028 if(c.dateValue == dt){
11038 findCells : function(ev) {
11039 var s = ev.start.clone().clearTime().getTime();
11041 var e= ev.end.clone().clearTime().getTime();
11044 this.cells.each(function(c){
11045 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11047 if(c.dateValue > e){
11050 if(c.dateValue < s){
11059 findBestRow: function(cells)
11063 for (var i =0 ; i < cells.length;i++) {
11064 ret = Math.max(cells[i].rows || 0,ret);
11071 addItem : function(ev)
11073 // look for vertical location slot in
11074 var cells = this.findCells(ev);
11076 ev.row = this.findBestRow(cells);
11078 // work out the location.
11082 for(var i =0; i < cells.length; i++) {
11090 if (crow.start.getY() == cells[i].getY()) {
11092 crow.end = cells[i];
11108 for (var i = 0; i < cells.length;i++) {
11109 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11113 this.calevents.push(ev);
11116 clearEvents: function() {
11118 if(!this.calevents){
11122 Roo.each(this.cells.elements, function(c){
11126 Roo.each(this.calevents, function(e) {
11127 Roo.each(e.els, function(el) {
11128 el.un('mouseenter' ,this.onEventEnter, this);
11129 el.un('mouseleave' ,this.onEventLeave, this);
11136 renderEvents: function()
11138 // first make sure there is enough space..
11140 this.cells.each(function(c) {
11142 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
11145 for (var e = 0; e < this.calevents.length; e++) {
11146 var ev = this.calevents[e];
11147 var cells = ev.cells;
11148 var rows = ev.rows;
11150 for(var i =0; i < rows.length; i++) {
11153 // how many rows should it span..
11156 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11157 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11159 unselectable : "on",
11162 cls: 'fc-event-inner',
11166 // cls: 'fc-event-time',
11167 // html : cells.length > 1 ? '' : ev.time
11171 cls: 'fc-event-title',
11172 html : String.format('{0}', ev.title)
11179 cls: 'ui-resizable-handle ui-resizable-e',
11180 html : '  '
11186 cfg.cls += ' fc-event-start';
11188 if ((i+1) == rows.length) {
11189 cfg.cls += ' fc-event-end';
11192 var ctr = this.el.select('.fc-event-container',true).first();
11193 var cg = ctr.createChild(cfg);
11195 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11196 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11197 cg.on('click', this.onEventClick, this, ev);
11201 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11202 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11204 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11205 cg.setWidth(ebox.right - sbox.x -2);
11213 onEventEnter: function (e, el,event,d) {
11214 this.fireEvent('evententer', this, el, event);
11217 onEventLeave: function (e, el,event,d) {
11218 this.fireEvent('eventleave', this, el, event);
11221 onEventClick: function (e, el,event,d) {
11222 this.fireEvent('eventclick', this, el, event);
11225 onMonthChange: function () {
11229 onLoad: function ()
11231 this.calevents = [];
11234 if(this.store.getCount() > 0){
11235 this.store.data.each(function(d){
11238 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11239 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11240 time : d.data.start_time,
11241 title : d.data.title,
11242 description : d.data.description,
11243 venue : d.data.venue
11248 this.renderEvents();
11251 this.maskEl.hide();
11255 onBeforeLoad: function()
11257 this.clearEvents();
11260 this.maskEl.show();
11274 * @class Roo.bootstrap.Popover
11275 * @extends Roo.bootstrap.Component
11276 * Bootstrap Popover class
11277 * @cfg {String} html contents of the popover (or false to use children..)
11278 * @cfg {String} title of popover (or false to hide)
11279 * @cfg {String} placement how it is placed
11280 * @cfg {String} trigger click || hover (or false to trigger manually)
11281 * @cfg {String} over what (parent or false to trigger manually.)
11284 * Create a new Popover
11285 * @param {Object} config The config object
11288 Roo.bootstrap.Popover = function(config){
11289 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11292 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11294 title: 'Fill in a title',
11297 placement : 'right',
11298 trigger : 'hover', // hover
11302 can_build_overlaid : false,
11304 getChildContainer : function()
11306 return this.el.select('.popover-content',true).first();
11309 getAutoCreate : function(){
11310 Roo.log('make popover?');
11312 cls : 'popover roo-dynamic',
11313 style: 'display:block',
11319 cls : 'popover-inner',
11323 cls: 'popover-title',
11327 cls : 'popover-content',
11338 setTitle: function(str)
11340 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11342 setContent: function(str)
11344 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11346 // as it get's added to the bottom of the page.
11347 onRender : function(ct, position)
11349 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11351 var cfg = Roo.apply({}, this.getAutoCreate());
11355 cfg.cls += ' ' + this.cls;
11358 cfg.style = this.style;
11360 Roo.log("adding to ")
11361 this.el = Roo.get(document.body).createChild(cfg, position);
11367 initEvents : function()
11369 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11370 this.el.enableDisplayMode('block');
11372 if (this.over === false) {
11375 if (this.triggers === false) {
11378 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11379 var triggers = this.trigger ? this.trigger.split(' ') : [];
11380 Roo.each(triggers, function(trigger) {
11382 if (trigger == 'click') {
11383 on_el.on('click', this.toggle, this);
11384 } else if (trigger != 'manual') {
11385 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11386 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11388 on_el.on(eventIn ,this.enter, this);
11389 on_el.on(eventOut, this.leave, this);
11400 toggle : function () {
11401 this.hoverState == 'in' ? this.leave() : this.enter();
11404 enter : function () {
11407 clearTimeout(this.timeout);
11409 this.hoverState = 'in'
11411 if (!this.delay || !this.delay.show) {
11416 this.timeout = setTimeout(function () {
11417 if (_t.hoverState == 'in') {
11420 }, this.delay.show)
11422 leave : function() {
11423 clearTimeout(this.timeout);
11425 this.hoverState = 'out'
11427 if (!this.delay || !this.delay.hide) {
11432 this.timeout = setTimeout(function () {
11433 if (_t.hoverState == 'out') {
11436 }, this.delay.hide)
11439 show : function (on_el)
11442 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11445 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11446 if (this.html !== false) {
11447 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11449 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11450 if (!this.title.length) {
11451 this.el.select('.popover-title',true).hide();
11454 var placement = typeof this.placement == 'function' ?
11455 this.placement.call(this, this.el, on_el) :
11458 var autoToken = /\s?auto?\s?/i;
11459 var autoPlace = autoToken.test(placement);
11461 placement = placement.replace(autoToken, '') || 'top';
11465 //this.el.setXY([0,0]);
11467 this.el.dom.style.display='block';
11468 this.el.addClass(placement);
11470 //this.el.appendTo(on_el);
11472 var p = this.getPosition();
11473 var box = this.el.getBox();
11478 var align = Roo.bootstrap.Popover.alignment[placement]
11479 this.el.alignTo(on_el, align[0],align[1]);
11480 //var arrow = this.el.select('.arrow',true).first();
11481 //arrow.set(align[2],
11483 this.el.addClass('in');
11484 this.hoverState = null;
11486 if (this.el.hasClass('fade')) {
11493 this.el.setXY([0,0]);
11494 this.el.removeClass('in');
11501 Roo.bootstrap.Popover.alignment = {
11502 'left' : ['r-l', [-10,0], 'right'],
11503 'right' : ['l-r', [10,0], 'left'],
11504 'bottom' : ['t-b', [0,10], 'top'],
11505 'top' : [ 'b-t', [0,-10], 'bottom']
11516 * @class Roo.bootstrap.Progress
11517 * @extends Roo.bootstrap.Component
11518 * Bootstrap Progress class
11519 * @cfg {Boolean} striped striped of the progress bar
11520 * @cfg {Boolean} active animated of the progress bar
11524 * Create a new Progress
11525 * @param {Object} config The config object
11528 Roo.bootstrap.Progress = function(config){
11529 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
11532 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
11537 getAutoCreate : function(){
11545 cfg.cls += ' progress-striped';
11549 cfg.cls += ' active';
11568 * @class Roo.bootstrap.ProgressBar
11569 * @extends Roo.bootstrap.Component
11570 * Bootstrap ProgressBar class
11571 * @cfg {Number} aria_valuenow aria-value now
11572 * @cfg {Number} aria_valuemin aria-value min
11573 * @cfg {Number} aria_valuemax aria-value max
11574 * @cfg {String} label label for the progress bar
11575 * @cfg {String} panel (success | info | warning | danger )
11576 * @cfg {String} role role of the progress bar
11577 * @cfg {String} sr_only text
11581 * Create a new ProgressBar
11582 * @param {Object} config The config object
11585 Roo.bootstrap.ProgressBar = function(config){
11586 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
11589 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
11593 aria_valuemax : 100,
11599 getAutoCreate : function()
11604 cls: 'progress-bar',
11605 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
11617 cfg.role = this.role;
11620 if(this.aria_valuenow){
11621 cfg['aria-valuenow'] = this.aria_valuenow;
11624 if(this.aria_valuemin){
11625 cfg['aria-valuemin'] = this.aria_valuemin;
11628 if(this.aria_valuemax){
11629 cfg['aria-valuemax'] = this.aria_valuemax;
11632 if(this.label && !this.sr_only){
11633 cfg.html = this.label;
11637 cfg.cls += ' progress-bar-' + this.panel;
11643 update : function(aria_valuenow)
11645 this.aria_valuenow = aria_valuenow;
11647 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11662 * @class Roo.bootstrap.TabPanel
11663 * @extends Roo.bootstrap.Component
11664 * Bootstrap TabPanel class
11665 * @cfg {Boolean} active panel active
11666 * @cfg {String} html panel content
11667 * @cfg {String} tabId tab relate id
11668 * @cfg {String} navId The navbar which triggers show hide
11672 * Create a new TabPanel
11673 * @param {Object} config The config object
11676 Roo.bootstrap.TabPanel = function(config){
11677 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11681 * Fires when the active status changes
11682 * @param {Roo.bootstrap.TabPanel} this
11683 * @param {Boolean} state the new state
11690 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11697 getAutoCreate : function(){
11701 html: this.html || ''
11705 cfg.cls += ' active';
11709 cfg.tabId = this.tabId;
11714 onRender : function(ct, position)
11716 // Roo.log("Call onRender: " + this.xtype);
11718 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11720 if (this.navId && this.tabId) {
11721 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11723 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11725 item.on('changed', function(item, state) {
11726 this.setActive(state);
11732 setActive: function(state)
11734 Roo.log("panel - set active " + this.tabId + "=" + state);
11736 this.active = state;
11738 this.el.removeClass('active');
11740 } else if (!this.el.hasClass('active')) {
11741 this.el.addClass('active');
11743 this.fireEvent('changed', this, state);
11760 * @class Roo.bootstrap.DateField
11761 * @extends Roo.bootstrap.Input
11762 * Bootstrap DateField class
11763 * @cfg {Number} weekStart default 0
11764 * @cfg {Number} weekStart default 0
11765 * @cfg {Number} viewMode default empty, (months|years)
11766 * @cfg {Number} minViewMode default empty, (months|years)
11767 * @cfg {Number} startDate default -Infinity
11768 * @cfg {Number} endDate default Infinity
11769 * @cfg {Boolean} todayHighlight default false
11770 * @cfg {Boolean} todayBtn default false
11771 * @cfg {Boolean} calendarWeeks default false
11772 * @cfg {Object} daysOfWeekDisabled default empty
11774 * @cfg {Boolean} keyboardNavigation default true
11775 * @cfg {String} language default en
11778 * Create a new DateField
11779 * @param {Object} config The config object
11782 Roo.bootstrap.DateField = function(config){
11783 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
11787 * Fires when this field show.
11788 * @param {Roo.bootstrap.DateField} this
11789 * @param {Mixed} date The date value
11794 * Fires when this field hide.
11795 * @param {Roo.bootstrap.DateField} this
11796 * @param {Mixed} date The date value
11801 * Fires when select a date.
11802 * @param {Roo.bootstrap.DateField} this
11803 * @param {Mixed} date The date value
11809 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11812 * @cfg {String} format
11813 * The default date format string which can be overriden for localization support. The format must be
11814 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11818 * @cfg {String} altFormats
11819 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11820 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11822 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11830 todayHighlight : false,
11836 keyboardNavigation: true,
11838 calendarWeeks: false,
11840 startDate: -Infinity,
11844 daysOfWeekDisabled: [],
11848 UTCDate: function()
11850 return new Date(Date.UTC.apply(Date, arguments));
11853 UTCToday: function()
11855 var today = new Date();
11856 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11859 getDate: function() {
11860 var d = this.getUTCDate();
11861 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11864 getUTCDate: function() {
11868 setDate: function(d) {
11869 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11872 setUTCDate: function(d) {
11874 this.setValue(this.formatDate(this.date));
11877 onRender: function(ct, position)
11880 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11882 this.language = this.language || 'en';
11883 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11884 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11886 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11887 this.format = this.format || 'm/d/y';
11888 this.isInline = false;
11889 this.isInput = true;
11890 this.component = this.el.select('.add-on', true).first() || false;
11891 this.component = (this.component && this.component.length === 0) ? false : this.component;
11892 this.hasInput = this.component && this.inputEL().length;
11894 if (typeof(this.minViewMode === 'string')) {
11895 switch (this.minViewMode) {
11897 this.minViewMode = 1;
11900 this.minViewMode = 2;
11903 this.minViewMode = 0;
11908 if (typeof(this.viewMode === 'string')) {
11909 switch (this.viewMode) {
11922 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11924 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11926 this.picker().on('mousedown', this.onMousedown, this);
11927 this.picker().on('click', this.onClick, this);
11929 this.picker().addClass('datepicker-dropdown');
11931 this.startViewMode = this.viewMode;
11934 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11935 if(!this.calendarWeeks){
11940 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11941 v.attr('colspan', function(i, val){
11942 return parseInt(val) + 1;
11947 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11949 this.setStartDate(this.startDate);
11950 this.setEndDate(this.endDate);
11952 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11959 if(this.isInline) {
11964 picker : function()
11966 return this.el.select('.datepicker', true).first();
11969 fillDow: function()
11971 var dowCnt = this.weekStart;
11980 if(this.calendarWeeks){
11988 while (dowCnt < this.weekStart + 7) {
11992 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11996 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11999 fillMonths: function()
12002 var months = this.picker().select('>.datepicker-months td', true).first();
12004 months.dom.innerHTML = '';
12010 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12013 months.createChild(month);
12018 update: function(){
12020 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12022 if (this.date < this.startDate) {
12023 this.viewDate = new Date(this.startDate);
12024 } else if (this.date > this.endDate) {
12025 this.viewDate = new Date(this.endDate);
12027 this.viewDate = new Date(this.date);
12034 var d = new Date(this.viewDate),
12035 year = d.getUTCFullYear(),
12036 month = d.getUTCMonth(),
12037 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12038 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12039 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12040 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12041 currentDate = this.date && this.date.valueOf(),
12042 today = this.UTCToday();
12044 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12046 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12048 // this.picker.select('>tfoot th.today').
12049 // .text(dates[this.language].today)
12050 // .toggle(this.todayBtn !== false);
12052 this.updateNavArrows();
12055 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12057 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12059 prevMonth.setUTCDate(day);
12061 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12063 var nextMonth = new Date(prevMonth);
12065 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12067 nextMonth = nextMonth.valueOf();
12069 var fillMonths = false;
12071 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12073 while(prevMonth.valueOf() < nextMonth) {
12076 if (prevMonth.getUTCDay() === this.weekStart) {
12078 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12086 if(this.calendarWeeks){
12087 // ISO 8601: First week contains first thursday.
12088 // ISO also states week starts on Monday, but we can be more abstract here.
12090 // Start of current week: based on weekstart/current date
12091 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12092 // Thursday of this week
12093 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12094 // First Thursday of year, year from thursday
12095 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12096 // Calendar week: ms between thursdays, div ms per day, div 7 days
12097 calWeek = (th - yth) / 864e5 / 7 + 1;
12099 fillMonths.cn.push({
12107 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12109 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12112 if (this.todayHighlight &&
12113 prevMonth.getUTCFullYear() == today.getFullYear() &&
12114 prevMonth.getUTCMonth() == today.getMonth() &&
12115 prevMonth.getUTCDate() == today.getDate()) {
12116 clsName += ' today';
12119 if (currentDate && prevMonth.valueOf() === currentDate) {
12120 clsName += ' active';
12123 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12124 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12125 clsName += ' disabled';
12128 fillMonths.cn.push({
12130 cls: 'day ' + clsName,
12131 html: prevMonth.getDate()
12134 prevMonth.setDate(prevMonth.getDate()+1);
12137 var currentYear = this.date && this.date.getUTCFullYear();
12138 var currentMonth = this.date && this.date.getUTCMonth();
12140 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12142 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12143 v.removeClass('active');
12145 if(currentYear === year && k === currentMonth){
12146 v.addClass('active');
12149 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12150 v.addClass('disabled');
12156 year = parseInt(year/10, 10) * 10;
12158 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12160 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12163 for (var i = -1; i < 11; i++) {
12164 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12166 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12174 showMode: function(dir) {
12176 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12178 Roo.each(this.picker().select('>div',true).elements, function(v){
12179 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12182 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12187 if(this.isInline) return;
12189 this.picker().removeClass(['bottom', 'top']);
12191 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12193 * place to the top of element!
12197 this.picker().addClass('top');
12198 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12203 this.picker().addClass('bottom');
12205 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12208 parseDate : function(value){
12209 if(!value || value instanceof Date){
12212 var v = Date.parseDate(value, this.format);
12213 if (!v && this.useIso) {
12214 v = Date.parseDate(value, 'Y-m-d');
12216 if(!v && this.altFormats){
12217 if(!this.altFormatsArray){
12218 this.altFormatsArray = this.altFormats.split("|");
12220 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12221 v = Date.parseDate(value, this.altFormatsArray[i]);
12227 formatDate : function(date, fmt){
12228 return (!date || !(date instanceof Date)) ?
12229 date : date.dateFormat(fmt || this.format);
12232 onFocus : function()
12234 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12238 onBlur : function()
12240 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12246 this.picker().show();
12250 this.fireEvent('show', this, this.date);
12255 if(this.isInline) return;
12256 this.picker().hide();
12257 this.viewMode = this.startViewMode;
12260 this.fireEvent('hide', this, this.date);
12264 onMousedown: function(e){
12265 e.stopPropagation();
12266 e.preventDefault();
12269 keyup: function(e){
12270 Roo.bootstrap.DateField.superclass.keyup.call(this);
12275 setValue: function(v){
12276 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12278 this.fireEvent('select', this, this.date);
12282 fireKey: function(e){
12283 if (!this.picker().isVisible()){
12284 if (e.keyCode == 27) // allow escape to hide and re-show picker
12288 var dateChanged = false,
12290 newDate, newViewDate;
12294 e.preventDefault();
12298 if (!this.keyboardNavigation) break;
12299 dir = e.keyCode == 37 ? -1 : 1;
12302 newDate = this.moveYear(this.date, dir);
12303 newViewDate = this.moveYear(this.viewDate, dir);
12304 } else if (e.shiftKey){
12305 newDate = this.moveMonth(this.date, dir);
12306 newViewDate = this.moveMonth(this.viewDate, dir);
12308 newDate = new Date(this.date);
12309 newDate.setUTCDate(this.date.getUTCDate() + dir);
12310 newViewDate = new Date(this.viewDate);
12311 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12313 if (this.dateWithinRange(newDate)){
12314 this.date = newDate;
12315 this.viewDate = newViewDate;
12316 this.setValue(this.formatDate(this.date));
12318 e.preventDefault();
12319 dateChanged = true;
12324 if (!this.keyboardNavigation) break;
12325 dir = e.keyCode == 38 ? -1 : 1;
12327 newDate = this.moveYear(this.date, dir);
12328 newViewDate = this.moveYear(this.viewDate, dir);
12329 } else if (e.shiftKey){
12330 newDate = this.moveMonth(this.date, dir);
12331 newViewDate = this.moveMonth(this.viewDate, dir);
12333 newDate = new Date(this.date);
12334 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12335 newViewDate = new Date(this.viewDate);
12336 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12338 if (this.dateWithinRange(newDate)){
12339 this.date = newDate;
12340 this.viewDate = newViewDate;
12341 this.setValue(this.formatDate(this.date));
12343 e.preventDefault();
12344 dateChanged = true;
12348 this.setValue(this.formatDate(this.date));
12350 e.preventDefault();
12353 this.setValue(this.formatDate(this.date));
12360 onClick: function(e) {
12361 e.stopPropagation();
12362 e.preventDefault();
12364 var target = e.getTarget();
12366 if(target.nodeName.toLowerCase() === 'i'){
12367 target = Roo.get(target).dom.parentNode;
12370 var nodeName = target.nodeName;
12371 var className = target.className;
12372 var html = target.innerHTML;
12374 switch(nodeName.toLowerCase()) {
12376 switch(className) {
12382 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12383 switch(this.viewMode){
12385 this.viewDate = this.moveMonth(this.viewDate, dir);
12389 this.viewDate = this.moveYear(this.viewDate, dir);
12395 var date = new Date();
12396 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12398 this.setValue(this.formatDate(this.date));
12404 if (className.indexOf('disabled') === -1) {
12405 this.viewDate.setUTCDate(1);
12406 if (className.indexOf('month') !== -1) {
12407 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12409 var year = parseInt(html, 10) || 0;
12410 this.viewDate.setUTCFullYear(year);
12419 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12420 var day = parseInt(html, 10) || 1;
12421 var year = this.viewDate.getUTCFullYear(),
12422 month = this.viewDate.getUTCMonth();
12424 if (className.indexOf('old') !== -1) {
12431 } else if (className.indexOf('new') !== -1) {
12439 this.date = this.UTCDate(year, month, day,0,0,0,0);
12440 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12442 this.setValue(this.formatDate(this.date));
12449 setStartDate: function(startDate){
12450 this.startDate = startDate || -Infinity;
12451 if (this.startDate !== -Infinity) {
12452 this.startDate = this.parseDate(this.startDate);
12455 this.updateNavArrows();
12458 setEndDate: function(endDate){
12459 this.endDate = endDate || Infinity;
12460 if (this.endDate !== Infinity) {
12461 this.endDate = this.parseDate(this.endDate);
12464 this.updateNavArrows();
12467 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
12468 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
12469 if (typeof(this.daysOfWeekDisabled) !== 'object') {
12470 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
12472 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
12473 return parseInt(d, 10);
12476 this.updateNavArrows();
12479 updateNavArrows: function() {
12480 var d = new Date(this.viewDate),
12481 year = d.getUTCFullYear(),
12482 month = d.getUTCMonth();
12484 Roo.each(this.picker().select('.prev', true).elements, function(v){
12486 switch (this.viewMode) {
12489 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
12495 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
12502 Roo.each(this.picker().select('.next', true).elements, function(v){
12504 switch (this.viewMode) {
12507 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
12513 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
12521 moveMonth: function(date, dir){
12522 if (!dir) return date;
12523 var new_date = new Date(date.valueOf()),
12524 day = new_date.getUTCDate(),
12525 month = new_date.getUTCMonth(),
12526 mag = Math.abs(dir),
12528 dir = dir > 0 ? 1 : -1;
12531 // If going back one month, make sure month is not current month
12532 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
12534 return new_date.getUTCMonth() == month;
12536 // If going forward one month, make sure month is as expected
12537 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
12539 return new_date.getUTCMonth() != new_month;
12541 new_month = month + dir;
12542 new_date.setUTCMonth(new_month);
12543 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
12544 if (new_month < 0 || new_month > 11)
12545 new_month = (new_month + 12) % 12;
12547 // For magnitudes >1, move one month at a time...
12548 for (var i=0; i<mag; i++)
12549 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
12550 new_date = this.moveMonth(new_date, dir);
12551 // ...then reset the day, keeping it in the new month
12552 new_month = new_date.getUTCMonth();
12553 new_date.setUTCDate(day);
12555 return new_month != new_date.getUTCMonth();
12558 // Common date-resetting loop -- if date is beyond end of month, make it
12561 new_date.setUTCDate(--day);
12562 new_date.setUTCMonth(new_month);
12567 moveYear: function(date, dir){
12568 return this.moveMonth(date, dir*12);
12571 dateWithinRange: function(date){
12572 return date >= this.startDate && date <= this.endDate;
12576 remove: function() {
12577 this.picker().remove();
12582 Roo.apply(Roo.bootstrap.DateField, {
12593 html: '<i class="icon-arrow-left"/>'
12603 html: '<i class="icon-arrow-right"/>'
12645 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12646 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12647 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12648 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12649 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12662 navFnc: 'FullYear',
12667 navFnc: 'FullYear',
12672 Roo.apply(Roo.bootstrap.DateField, {
12676 cls: 'datepicker dropdown-menu',
12680 cls: 'datepicker-days',
12684 cls: 'table-condensed',
12686 Roo.bootstrap.DateField.head,
12690 Roo.bootstrap.DateField.footer
12697 cls: 'datepicker-months',
12701 cls: 'table-condensed',
12703 Roo.bootstrap.DateField.head,
12704 Roo.bootstrap.DateField.content,
12705 Roo.bootstrap.DateField.footer
12712 cls: 'datepicker-years',
12716 cls: 'table-condensed',
12718 Roo.bootstrap.DateField.head,
12719 Roo.bootstrap.DateField.content,
12720 Roo.bootstrap.DateField.footer
12739 * @class Roo.bootstrap.TimeField
12740 * @extends Roo.bootstrap.Input
12741 * Bootstrap DateField class
12745 * Create a new TimeField
12746 * @param {Object} config The config object
12749 Roo.bootstrap.TimeField = function(config){
12750 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12754 * Fires when this field show.
12755 * @param {Roo.bootstrap.DateField} this
12756 * @param {Mixed} date The date value
12761 * Fires when this field hide.
12762 * @param {Roo.bootstrap.DateField} this
12763 * @param {Mixed} date The date value
12768 * Fires when select a date.
12769 * @param {Roo.bootstrap.DateField} this
12770 * @param {Mixed} date The date value
12776 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
12779 * @cfg {String} format
12780 * The default time format string which can be overriden for localization support. The format must be
12781 * valid according to {@link Date#parseDate} (defaults to 'H:i').
12785 onRender: function(ct, position)
12788 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
12790 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
12792 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12794 this.pop = this.picker().select('>.datepicker-time',true).first();
12795 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12797 this.picker().on('mousedown', this.onMousedown, this);
12798 this.picker().on('click', this.onClick, this);
12800 this.picker().addClass('datepicker-dropdown');
12805 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12806 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12807 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12808 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12809 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12810 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12814 fireKey: function(e){
12815 if (!this.picker().isVisible()){
12816 if (e.keyCode == 27) // allow escape to hide and re-show picker
12821 e.preventDefault();
12829 this.onTogglePeriod();
12832 this.onIncrementMinutes();
12835 this.onDecrementMinutes();
12844 onClick: function(e) {
12845 e.stopPropagation();
12846 e.preventDefault();
12849 picker : function()
12851 return this.el.select('.datepicker', true).first();
12854 fillTime: function()
12856 var time = this.pop.select('tbody', true).first();
12858 time.dom.innerHTML = '';
12873 cls: 'hours-up glyphicon glyphicon-chevron-up'
12893 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12914 cls: 'timepicker-hour',
12929 cls: 'timepicker-minute',
12944 cls: 'btn btn-primary period',
12966 cls: 'hours-down glyphicon glyphicon-chevron-down'
12986 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13004 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13011 var hours = this.time.getHours();
13012 var minutes = this.time.getMinutes();
13025 hours = hours - 12;
13029 hours = '0' + hours;
13033 minutes = '0' + minutes;
13036 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13037 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13038 this.pop.select('button', true).first().dom.innerHTML = period;
13044 this.picker().removeClass(['bottom', 'top']);
13046 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13048 * place to the top of element!
13052 this.picker().addClass('top');
13053 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13058 this.picker().addClass('bottom');
13060 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13063 onFocus : function()
13065 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13069 onBlur : function()
13071 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13077 this.picker().show();
13082 this.fireEvent('show', this, this.date);
13087 this.picker().hide();
13090 this.fireEvent('hide', this, this.date);
13093 setTime : function()
13096 this.setValue(this.time.format(this.format));
13098 this.fireEvent('select', this, this.date);
13103 onMousedown: function(e){
13104 e.stopPropagation();
13105 e.preventDefault();
13108 onIncrementHours: function()
13110 Roo.log('onIncrementHours');
13111 this.time = this.time.add(Date.HOUR, 1);
13116 onDecrementHours: function()
13118 Roo.log('onDecrementHours');
13119 this.time = this.time.add(Date.HOUR, -1);
13123 onIncrementMinutes: function()
13125 Roo.log('onIncrementMinutes');
13126 this.time = this.time.add(Date.MINUTE, 1);
13130 onDecrementMinutes: function()
13132 Roo.log('onDecrementMinutes');
13133 this.time = this.time.add(Date.MINUTE, -1);
13137 onTogglePeriod: function()
13139 Roo.log('onTogglePeriod');
13140 this.time = this.time.add(Date.HOUR, 12);
13147 Roo.apply(Roo.bootstrap.TimeField, {
13177 cls: 'btn btn-info ok',
13189 Roo.apply(Roo.bootstrap.TimeField, {
13193 cls: 'datepicker dropdown-menu',
13197 cls: 'datepicker-time',
13201 cls: 'table-condensed',
13203 Roo.bootstrap.TimeField.content,
13204 Roo.bootstrap.TimeField.footer
13223 * @class Roo.bootstrap.CheckBox
13224 * @extends Roo.bootstrap.Input
13225 * Bootstrap CheckBox class
13227 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13228 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13229 * @cfg {String} boxLabel The text that appears beside the checkbox
13230 * @cfg {Boolean} checked initnal the element
13233 * Create a new CheckBox
13234 * @param {Object} config The config object
13237 Roo.bootstrap.CheckBox = function(config){
13238 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13243 * Fires when the element is checked or unchecked.
13244 * @param {Roo.bootstrap.CheckBox} this This input
13245 * @param {Boolean} checked The new checked value
13251 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13253 inputType: 'checkbox',
13259 getAutoCreate : function()
13261 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13267 cfg.cls = 'form-group' //input-group
13272 type : this.inputType,
13273 value : (!this.checked) ? this.valueOff : this.inputValue,
13275 placeholder : this.placeholder || ''
13279 if (this.disabled) {
13280 input.disabled=true;
13284 input.checked = this.checked;
13288 input.name = this.name;
13292 input.cls += ' input-' + this.size;
13296 ['xs','sm','md','lg'].map(function(size){
13297 if (settings[size]) {
13298 cfg.cls += ' col-' + size + '-' + settings[size];
13302 var inputblock = input;
13304 if (this.before || this.after) {
13307 cls : 'input-group',
13311 inputblock.cn.push({
13313 cls : 'input-group-addon',
13317 inputblock.cn.push(input);
13319 inputblock.cn.push({
13321 cls : 'input-group-addon',
13328 if (align ==='left' && this.fieldLabel.length) {
13329 Roo.log("left and has label");
13335 cls : 'control-label col-md-' + this.labelWidth,
13336 html : this.fieldLabel
13340 cls : "col-md-" + (12 - this.labelWidth),
13347 } else if ( this.fieldLabel.length) {
13352 tag: this.boxLabel ? 'span' : 'label',
13354 cls: 'control-label box-input-label',
13355 //cls : 'input-group-addon',
13356 html : this.fieldLabel
13366 Roo.log(" no label && no align");
13381 html: this.boxLabel
13390 * return the real input element.
13392 inputEl: function ()
13394 return this.el.select('input.form-box',true).first();
13397 initEvents : function()
13399 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13401 this.inputEl().on('click', this.onClick, this);
13405 onClick : function()
13407 this.setChecked(!this.checked);
13410 setChecked : function(state,suppressEvent)
13412 this.checked = state;
13414 this.inputEl().dom.checked = state;
13416 if(suppressEvent !== true){
13417 this.fireEvent('check', this, state);
13420 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13424 setValue : function(v,suppressEvent)
13426 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
13440 * @class Roo.bootstrap.Radio
13441 * @extends Roo.bootstrap.CheckBox
13442 * Bootstrap Radio class
13445 * Create a new Radio
13446 * @param {Object} config The config object
13449 Roo.bootstrap.Radio = function(config){
13450 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
13454 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
13456 inputType: 'radio',
13460 getAutoCreate : function()
13462 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13468 cfg.cls = 'form-group' //input-group
13473 type : this.inputType,
13474 value : (!this.checked) ? this.valueOff : this.inputValue,
13476 placeholder : this.placeholder || ''
13480 if (this.disabled) {
13481 input.disabled=true;
13485 input.checked = this.checked;
13489 input.name = this.name;
13493 input.cls += ' input-' + this.size;
13497 ['xs','sm','md','lg'].map(function(size){
13498 if (settings[size]) {
13499 cfg.cls += ' col-' + size + '-' + settings[size];
13503 var inputblock = input;
13505 if (this.before || this.after) {
13508 cls : 'input-group',
13512 inputblock.cn.push({
13514 cls : 'input-group-addon',
13518 inputblock.cn.push(input);
13520 inputblock.cn.push({
13522 cls : 'input-group-addon',
13529 if (align ==='left' && this.fieldLabel.length) {
13530 Roo.log("left and has label");
13536 cls : 'control-label col-md-' + this.labelWidth,
13537 html : this.fieldLabel
13541 cls : "col-md-" + (12 - this.labelWidth),
13548 } else if ( this.fieldLabel.length) {
13555 cls: 'control-label box-input-label',
13556 //cls : 'input-group-addon',
13557 html : this.fieldLabel
13567 Roo.log(" no label && no align");
13582 html: this.boxLabel
13590 onClick : function()
13592 this.setChecked(true);
13595 setChecked : function(state,suppressEvent)
13598 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13599 v.dom.checked = false;
13603 this.checked = state;
13604 this.inputEl().dom.checked = state;
13606 if(suppressEvent !== true){
13607 this.fireEvent('check', this, state);
13610 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13614 getGroupValue : function()
13617 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13618 if(v.dom.checked == true){
13619 value = v.dom.value;
13627 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
13628 * @return {Mixed} value The field value
13630 getValue : function(){
13631 return this.getGroupValue();
13637 //<script type="text/javascript">
13640 * Based Ext JS Library 1.1.1
13641 * Copyright(c) 2006-2007, Ext JS, LLC.
13647 * @class Roo.HtmlEditorCore
13648 * @extends Roo.Component
13649 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13651 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13654 Roo.HtmlEditorCore = function(config){
13657 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13660 * @event initialize
13661 * Fires when the editor is fully initialized (including the iframe)
13662 * @param {Roo.HtmlEditorCore} this
13667 * Fires when the editor is first receives the focus. Any insertion must wait
13668 * until after this event.
13669 * @param {Roo.HtmlEditorCore} this
13673 * @event beforesync
13674 * Fires before the textarea is updated with content from the editor iframe. Return false
13675 * to cancel the sync.
13676 * @param {Roo.HtmlEditorCore} this
13677 * @param {String} html
13681 * @event beforepush
13682 * Fires before the iframe editor is updated with content from the textarea. Return false
13683 * to cancel the push.
13684 * @param {Roo.HtmlEditorCore} this
13685 * @param {String} html
13690 * Fires when the textarea is updated with content from the editor iframe.
13691 * @param {Roo.HtmlEditorCore} this
13692 * @param {String} html
13697 * Fires when the iframe editor is updated with content from the textarea.
13698 * @param {Roo.HtmlEditorCore} this
13699 * @param {String} html
13704 * @event editorevent
13705 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13706 * @param {Roo.HtmlEditorCore} this
13714 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13718 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13724 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13729 * @cfg {Number} height (in pixels)
13733 * @cfg {Number} width (in pixels)
13738 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13741 stylesheets: false,
13746 // private properties
13747 validationEvent : false,
13749 initialized : false,
13751 sourceEditMode : false,
13752 onFocus : Roo.emptyFn,
13754 hideMode:'offsets',
13762 * Protected method that will not generally be called directly. It
13763 * is called when the editor initializes the iframe with HTML contents. Override this method if you
13764 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
13766 getDocMarkup : function(){
13769 Roo.log(this.stylesheets);
13771 // inherit styels from page...??
13772 if (this.stylesheets === false) {
13774 Roo.get(document.head).select('style').each(function(node) {
13775 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13778 Roo.get(document.head).select('link').each(function(node) {
13779 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13782 } else if (!this.stylesheets.length) {
13784 st = '<style type="text/css">' +
13785 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13788 Roo.each(this.stylesheets, function(s) {
13789 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
13794 st += '<style type="text/css">' +
13795 'IMG { cursor: pointer } ' +
13799 return '<html><head>' + st +
13800 //<style type="text/css">' +
13801 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13803 ' </head><body class="roo-htmleditor-body"></body></html>';
13807 onRender : function(ct, position)
13810 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13811 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13814 this.el.dom.style.border = '0 none';
13815 this.el.dom.setAttribute('tabIndex', -1);
13816 this.el.addClass('x-hidden hide');
13820 if(Roo.isIE){ // fix IE 1px bogus margin
13821 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13825 this.frameId = Roo.id();
13829 var iframe = this.owner.wrap.createChild({
13831 cls: 'form-control', // bootstrap..
13833 name: this.frameId,
13834 frameBorder : 'no',
13835 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
13840 this.iframe = iframe.dom;
13842 this.assignDocWin();
13844 this.doc.designMode = 'on';
13847 this.doc.write(this.getDocMarkup());
13851 var task = { // must defer to wait for browser to be ready
13853 //console.log("run task?" + this.doc.readyState);
13854 this.assignDocWin();
13855 if(this.doc.body || this.doc.readyState == 'complete'){
13857 this.doc.designMode="on";
13861 Roo.TaskMgr.stop(task);
13862 this.initEditor.defer(10, this);
13869 Roo.TaskMgr.start(task);
13876 onResize : function(w, h)
13878 Roo.log('resize: ' +w + ',' + h );
13879 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13883 if(typeof w == 'number'){
13885 this.iframe.style.width = w + 'px';
13887 if(typeof h == 'number'){
13889 this.iframe.style.height = h + 'px';
13891 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13898 * Toggles the editor between standard and source edit mode.
13899 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13901 toggleSourceEdit : function(sourceEditMode){
13903 this.sourceEditMode = sourceEditMode === true;
13905 if(this.sourceEditMode){
13907 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13910 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13911 //this.iframe.className = '';
13914 //this.setSize(this.owner.wrap.getSize());
13915 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13922 * Protected method that will not generally be called directly. If you need/want
13923 * custom HTML cleanup, this is the method you should override.
13924 * @param {String} html The HTML to be cleaned
13925 * return {String} The cleaned HTML
13927 cleanHtml : function(html){
13928 html = String(html);
13929 if(html.length > 5){
13930 if(Roo.isSafari){ // strip safari nonsense
13931 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13934 if(html == ' '){
13941 * HTML Editor -> Textarea
13942 * Protected method that will not generally be called directly. Syncs the contents
13943 * of the editor iframe with the textarea.
13945 syncValue : function(){
13946 if(this.initialized){
13947 var bd = (this.doc.body || this.doc.documentElement);
13948 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13949 var html = bd.innerHTML;
13951 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13952 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13954 html = '<div style="'+m[0]+'">' + html + '</div>';
13957 html = this.cleanHtml(html);
13958 // fix up the special chars.. normaly like back quotes in word...
13959 // however we do not want to do this with chinese..
13960 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13961 var cc = b.charCodeAt();
13963 (cc >= 0x4E00 && cc < 0xA000 ) ||
13964 (cc >= 0x3400 && cc < 0x4E00 ) ||
13965 (cc >= 0xf900 && cc < 0xfb00 )
13971 if(this.owner.fireEvent('beforesync', this, html) !== false){
13972 this.el.dom.value = html;
13973 this.owner.fireEvent('sync', this, html);
13979 * Protected method that will not generally be called directly. Pushes the value of the textarea
13980 * into the iframe editor.
13982 pushValue : function(){
13983 if(this.initialized){
13984 var v = this.el.dom.value.trim();
13986 // if(v.length < 1){
13990 if(this.owner.fireEvent('beforepush', this, v) !== false){
13991 var d = (this.doc.body || this.doc.documentElement);
13993 this.cleanUpPaste();
13994 this.el.dom.value = d.innerHTML;
13995 this.owner.fireEvent('push', this, v);
14001 deferFocus : function(){
14002 this.focus.defer(10, this);
14006 focus : function(){
14007 if(this.win && !this.sourceEditMode){
14014 assignDocWin: function()
14016 var iframe = this.iframe;
14019 this.doc = iframe.contentWindow.document;
14020 this.win = iframe.contentWindow;
14022 if (!Roo.get(this.frameId)) {
14025 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14026 this.win = Roo.get(this.frameId).dom.contentWindow;
14031 initEditor : function(){
14032 //console.log("INIT EDITOR");
14033 this.assignDocWin();
14037 this.doc.designMode="on";
14039 this.doc.write(this.getDocMarkup());
14042 var dbody = (this.doc.body || this.doc.documentElement);
14043 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14044 // this copies styles from the containing element into thsi one..
14045 // not sure why we need all of this..
14046 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14047 ss['background-attachment'] = 'fixed'; // w3c
14048 dbody.bgProperties = 'fixed'; // ie
14049 Roo.DomHelper.applyStyles(dbody, ss);
14050 Roo.EventManager.on(this.doc, {
14051 //'mousedown': this.onEditorEvent,
14052 'mouseup': this.onEditorEvent,
14053 'dblclick': this.onEditorEvent,
14054 'click': this.onEditorEvent,
14055 'keyup': this.onEditorEvent,
14060 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14062 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14063 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14065 this.initialized = true;
14067 this.owner.fireEvent('initialize', this);
14072 onDestroy : function(){
14078 //for (var i =0; i < this.toolbars.length;i++) {
14079 // // fixme - ask toolbars for heights?
14080 // this.toolbars[i].onDestroy();
14083 //this.wrap.dom.innerHTML = '';
14084 //this.wrap.remove();
14089 onFirstFocus : function(){
14091 this.assignDocWin();
14094 this.activated = true;
14097 if(Roo.isGecko){ // prevent silly gecko errors
14099 var s = this.win.getSelection();
14100 if(!s.focusNode || s.focusNode.nodeType != 3){
14101 var r = s.getRangeAt(0);
14102 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14107 this.execCmd('useCSS', true);
14108 this.execCmd('styleWithCSS', false);
14111 this.owner.fireEvent('activate', this);
14115 adjustFont: function(btn){
14116 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14117 //if(Roo.isSafari){ // safari
14120 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14121 if(Roo.isSafari){ // safari
14122 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14123 v = (v < 10) ? 10 : v;
14124 v = (v > 48) ? 48 : v;
14125 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14130 v = Math.max(1, v+adjust);
14132 this.execCmd('FontSize', v );
14135 onEditorEvent : function(e){
14136 this.owner.fireEvent('editorevent', this, e);
14137 // this.updateToolbar();
14138 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14141 insertTag : function(tg)
14143 // could be a bit smarter... -> wrap the current selected tRoo..
14144 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14146 range = this.createRange(this.getSelection());
14147 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14148 wrappingNode.appendChild(range.extractContents());
14149 range.insertNode(wrappingNode);
14156 this.execCmd("formatblock", tg);
14160 insertText : function(txt)
14164 var range = this.createRange();
14165 range.deleteContents();
14166 //alert(Sender.getAttribute('label'));
14168 range.insertNode(this.doc.createTextNode(txt));
14174 * Executes a Midas editor command on the editor document and performs necessary focus and
14175 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14176 * @param {String} cmd The Midas command
14177 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14179 relayCmd : function(cmd, value){
14181 this.execCmd(cmd, value);
14182 this.owner.fireEvent('editorevent', this);
14183 //this.updateToolbar();
14184 this.owner.deferFocus();
14188 * Executes a Midas editor command directly on the editor document.
14189 * For visual commands, you should use {@link #relayCmd} instead.
14190 * <b>This should only be called after the editor is initialized.</b>
14191 * @param {String} cmd The Midas command
14192 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14194 execCmd : function(cmd, value){
14195 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14202 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14204 * @param {String} text | dom node..
14206 insertAtCursor : function(text)
14211 if(!this.activated){
14217 var r = this.doc.selection.createRange();
14228 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14232 // from jquery ui (MIT licenced)
14234 var win = this.win;
14236 if (win.getSelection && win.getSelection().getRangeAt) {
14237 range = win.getSelection().getRangeAt(0);
14238 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14239 range.insertNode(node);
14240 } else if (win.document.selection && win.document.selection.createRange) {
14241 // no firefox support
14242 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14243 win.document.selection.createRange().pasteHTML(txt);
14245 // no firefox support
14246 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14247 this.execCmd('InsertHTML', txt);
14256 mozKeyPress : function(e){
14258 var c = e.getCharCode(), cmd;
14261 c = String.fromCharCode(c).toLowerCase();
14275 this.cleanUpPaste.defer(100, this);
14283 e.preventDefault();
14291 fixKeys : function(){ // load time branching for fastest keydown performance
14293 return function(e){
14294 var k = e.getKey(), r;
14297 r = this.doc.selection.createRange();
14300 r.pasteHTML('    ');
14307 r = this.doc.selection.createRange();
14309 var target = r.parentElement();
14310 if(!target || target.tagName.toLowerCase() != 'li'){
14312 r.pasteHTML('<br />');
14318 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14319 this.cleanUpPaste.defer(100, this);
14325 }else if(Roo.isOpera){
14326 return function(e){
14327 var k = e.getKey();
14331 this.execCmd('InsertHTML','    ');
14334 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14335 this.cleanUpPaste.defer(100, this);
14340 }else if(Roo.isSafari){
14341 return function(e){
14342 var k = e.getKey();
14346 this.execCmd('InsertText','\t');
14350 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14351 this.cleanUpPaste.defer(100, this);
14359 getAllAncestors: function()
14361 var p = this.getSelectedNode();
14364 a.push(p); // push blank onto stack..
14365 p = this.getParentElement();
14369 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14373 a.push(this.doc.body);
14377 lastSelNode : false,
14380 getSelection : function()
14382 this.assignDocWin();
14383 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14386 getSelectedNode: function()
14388 // this may only work on Gecko!!!
14390 // should we cache this!!!!
14395 var range = this.createRange(this.getSelection()).cloneRange();
14398 var parent = range.parentElement();
14400 var testRange = range.duplicate();
14401 testRange.moveToElementText(parent);
14402 if (testRange.inRange(range)) {
14405 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14408 parent = parent.parentElement;
14413 // is ancestor a text element.
14414 var ac = range.commonAncestorContainer;
14415 if (ac.nodeType == 3) {
14416 ac = ac.parentNode;
14419 var ar = ac.childNodes;
14422 var other_nodes = [];
14423 var has_other_nodes = false;
14424 for (var i=0;i<ar.length;i++) {
14425 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14428 // fullly contained node.
14430 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
14435 // probably selected..
14436 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
14437 other_nodes.push(ar[i]);
14441 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
14446 has_other_nodes = true;
14448 if (!nodes.length && other_nodes.length) {
14449 nodes= other_nodes;
14451 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
14457 createRange: function(sel)
14459 // this has strange effects when using with
14460 // top toolbar - not sure if it's a great idea.
14461 //this.editor.contentWindow.focus();
14462 if (typeof sel != "undefined") {
14464 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
14466 return this.doc.createRange();
14469 return this.doc.createRange();
14472 getParentElement: function()
14475 this.assignDocWin();
14476 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
14478 var range = this.createRange(sel);
14481 var p = range.commonAncestorContainer;
14482 while (p.nodeType == 3) { // text node
14493 * Range intersection.. the hard stuff...
14497 * [ -- selected range --- ]
14501 * if end is before start or hits it. fail.
14502 * if start is after end or hits it fail.
14504 * if either hits (but other is outside. - then it's not
14510 // @see http://www.thismuchiknow.co.uk/?p=64.
14511 rangeIntersectsNode : function(range, node)
14513 var nodeRange = node.ownerDocument.createRange();
14515 nodeRange.selectNode(node);
14517 nodeRange.selectNodeContents(node);
14520 var rangeStartRange = range.cloneRange();
14521 rangeStartRange.collapse(true);
14523 var rangeEndRange = range.cloneRange();
14524 rangeEndRange.collapse(false);
14526 var nodeStartRange = nodeRange.cloneRange();
14527 nodeStartRange.collapse(true);
14529 var nodeEndRange = nodeRange.cloneRange();
14530 nodeEndRange.collapse(false);
14532 return rangeStartRange.compareBoundaryPoints(
14533 Range.START_TO_START, nodeEndRange) == -1 &&
14534 rangeEndRange.compareBoundaryPoints(
14535 Range.START_TO_START, nodeStartRange) == 1;
14539 rangeCompareNode : function(range, node)
14541 var nodeRange = node.ownerDocument.createRange();
14543 nodeRange.selectNode(node);
14545 nodeRange.selectNodeContents(node);
14549 range.collapse(true);
14551 nodeRange.collapse(true);
14553 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
14554 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
14556 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
14558 var nodeIsBefore = ss == 1;
14559 var nodeIsAfter = ee == -1;
14561 if (nodeIsBefore && nodeIsAfter)
14563 if (!nodeIsBefore && nodeIsAfter)
14564 return 1; //right trailed.
14566 if (nodeIsBefore && !nodeIsAfter)
14567 return 2; // left trailed.
14572 // private? - in a new class?
14573 cleanUpPaste : function()
14575 // cleans up the whole document..
14576 Roo.log('cleanuppaste');
14578 this.cleanUpChildren(this.doc.body);
14579 var clean = this.cleanWordChars(this.doc.body.innerHTML);
14580 if (clean != this.doc.body.innerHTML) {
14581 this.doc.body.innerHTML = clean;
14586 cleanWordChars : function(input) {// change the chars to hex code
14587 var he = Roo.HtmlEditorCore;
14589 var output = input;
14590 Roo.each(he.swapCodes, function(sw) {
14591 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
14593 output = output.replace(swapper, sw[1]);
14600 cleanUpChildren : function (n)
14602 if (!n.childNodes.length) {
14605 for (var i = n.childNodes.length-1; i > -1 ; i--) {
14606 this.cleanUpChild(n.childNodes[i]);
14613 cleanUpChild : function (node)
14616 //console.log(node);
14617 if (node.nodeName == "#text") {
14618 // clean up silly Windows -- stuff?
14621 if (node.nodeName == "#comment") {
14622 node.parentNode.removeChild(node);
14623 // clean up silly Windows -- stuff?
14627 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
14629 node.parentNode.removeChild(node);
14634 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
14636 // remove <a name=....> as rendering on yahoo mailer is borked with this.
14637 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14639 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14640 // remove_keep_children = true;
14643 if (remove_keep_children) {
14644 this.cleanUpChildren(node);
14645 // inserts everything just before this node...
14646 while (node.childNodes.length) {
14647 var cn = node.childNodes[0];
14648 node.removeChild(cn);
14649 node.parentNode.insertBefore(cn, node);
14651 node.parentNode.removeChild(node);
14655 if (!node.attributes || !node.attributes.length) {
14656 this.cleanUpChildren(node);
14660 function cleanAttr(n,v)
14663 if (v.match(/^\./) || v.match(/^\//)) {
14666 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14669 if (v.match(/^#/)) {
14672 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14673 node.removeAttribute(n);
14677 function cleanStyle(n,v)
14679 if (v.match(/expression/)) { //XSS?? should we even bother..
14680 node.removeAttribute(n);
14683 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14684 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14687 var parts = v.split(/;/);
14690 Roo.each(parts, function(p) {
14691 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14695 var l = p.split(':').shift().replace(/\s+/g,'');
14696 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14698 if ( cblack.indexOf(l) > -1) {
14699 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14700 //node.removeAttribute(n);
14704 // only allow 'c whitelisted system attributes'
14705 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14706 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14707 //node.removeAttribute(n);
14717 if (clean.length) {
14718 node.setAttribute(n, clean.join(';'));
14720 node.removeAttribute(n);
14726 for (var i = node.attributes.length-1; i > -1 ; i--) {
14727 var a = node.attributes[i];
14730 if (a.name.toLowerCase().substr(0,2)=='on') {
14731 node.removeAttribute(a.name);
14734 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14735 node.removeAttribute(a.name);
14738 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14739 cleanAttr(a.name,a.value); // fixme..
14742 if (a.name == 'style') {
14743 cleanStyle(a.name,a.value);
14746 /// clean up MS crap..
14747 // tecnically this should be a list of valid class'es..
14750 if (a.name == 'class') {
14751 if (a.value.match(/^Mso/)) {
14752 node.className = '';
14755 if (a.value.match(/body/)) {
14756 node.className = '';
14767 this.cleanUpChildren(node);
14773 // hide stuff that is not compatible
14787 * @event specialkey
14791 * @cfg {String} fieldClass @hide
14794 * @cfg {String} focusClass @hide
14797 * @cfg {String} autoCreate @hide
14800 * @cfg {String} inputType @hide
14803 * @cfg {String} invalidClass @hide
14806 * @cfg {String} invalidText @hide
14809 * @cfg {String} msgFx @hide
14812 * @cfg {String} validateOnBlur @hide
14816 Roo.HtmlEditorCore.white = [
14817 'area', 'br', 'img', 'input', 'hr', 'wbr',
14819 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14820 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14821 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14822 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14823 'table', 'ul', 'xmp',
14825 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14828 'dir', 'menu', 'ol', 'ul', 'dl',
14834 Roo.HtmlEditorCore.black = [
14835 // 'embed', 'object', // enable - backend responsiblity to clean thiese
14837 'base', 'basefont', 'bgsound', 'blink', 'body',
14838 'frame', 'frameset', 'head', 'html', 'ilayer',
14839 'iframe', 'layer', 'link', 'meta', 'object',
14840 'script', 'style' ,'title', 'xml' // clean later..
14842 Roo.HtmlEditorCore.clean = [
14843 'script', 'style', 'title', 'xml'
14845 Roo.HtmlEditorCore.remove = [
14850 Roo.HtmlEditorCore.ablack = [
14854 Roo.HtmlEditorCore.aclean = [
14855 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14859 Roo.HtmlEditorCore.pwhite= [
14860 'http', 'https', 'mailto'
14863 // white listed style attributes.
14864 Roo.HtmlEditorCore.cwhite= [
14865 // 'text-align', /// default is to allow most things..
14871 // black listed style attributes.
14872 Roo.HtmlEditorCore.cblack= [
14873 // 'font-size' -- this can be set by the project
14877 Roo.HtmlEditorCore.swapCodes =[
14896 * @class Roo.bootstrap.HtmlEditor
14897 * @extends Roo.bootstrap.TextArea
14898 * Bootstrap HtmlEditor class
14901 * Create a new HtmlEditor
14902 * @param {Object} config The config object
14905 Roo.bootstrap.HtmlEditor = function(config){
14906 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14907 if (!this.toolbars) {
14908 this.toolbars = [];
14910 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14913 * @event initialize
14914 * Fires when the editor is fully initialized (including the iframe)
14915 * @param {HtmlEditor} this
14920 * Fires when the editor is first receives the focus. Any insertion must wait
14921 * until after this event.
14922 * @param {HtmlEditor} this
14926 * @event beforesync
14927 * Fires before the textarea is updated with content from the editor iframe. Return false
14928 * to cancel the sync.
14929 * @param {HtmlEditor} this
14930 * @param {String} html
14934 * @event beforepush
14935 * Fires before the iframe editor is updated with content from the textarea. Return false
14936 * to cancel the push.
14937 * @param {HtmlEditor} this
14938 * @param {String} html
14943 * Fires when the textarea is updated with content from the editor iframe.
14944 * @param {HtmlEditor} this
14945 * @param {String} html
14950 * Fires when the iframe editor is updated with content from the textarea.
14951 * @param {HtmlEditor} this
14952 * @param {String} html
14956 * @event editmodechange
14957 * Fires when the editor switches edit modes
14958 * @param {HtmlEditor} this
14959 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14961 editmodechange: true,
14963 * @event editorevent
14964 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14965 * @param {HtmlEditor} this
14969 * @event firstfocus
14970 * Fires when on first focus - needed by toolbars..
14971 * @param {HtmlEditor} this
14976 * Auto save the htmlEditor value as a file into Events
14977 * @param {HtmlEditor} this
14981 * @event savedpreview
14982 * preview the saved version of htmlEditor
14983 * @param {HtmlEditor} this
14990 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14994 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14999 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15004 * @cfg {Number} height (in pixels)
15008 * @cfg {Number} width (in pixels)
15013 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15016 stylesheets: false,
15021 // private properties
15022 validationEvent : false,
15024 initialized : false,
15027 onFocus : Roo.emptyFn,
15029 hideMode:'offsets',
15032 tbContainer : false,
15034 toolbarContainer :function() {
15035 return this.wrap.select('.x-html-editor-tb',true).first();
15039 * Protected method that will not generally be called directly. It
15040 * is called when the editor creates its toolbar. Override this method if you need to
15041 * add custom toolbar buttons.
15042 * @param {HtmlEditor} editor
15044 createToolbar : function(){
15046 Roo.log("create toolbars");
15048 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15049 this.toolbars[0].render(this.toolbarContainer());
15053 // if (!editor.toolbars || !editor.toolbars.length) {
15054 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15057 // for (var i =0 ; i < editor.toolbars.length;i++) {
15058 // editor.toolbars[i] = Roo.factory(
15059 // typeof(editor.toolbars[i]) == 'string' ?
15060 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15061 // Roo.bootstrap.HtmlEditor);
15062 // editor.toolbars[i].init(editor);
15068 onRender : function(ct, position)
15070 // Roo.log("Call onRender: " + this.xtype);
15072 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15074 this.wrap = this.inputEl().wrap({
15075 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15078 this.editorcore.onRender(ct, position);
15080 if (this.resizable) {
15081 this.resizeEl = new Roo.Resizable(this.wrap, {
15085 minHeight : this.height,
15086 height: this.height,
15087 handles : this.resizable,
15090 resize : function(r, w, h) {
15091 _t.onResize(w,h); // -something
15097 this.createToolbar(this);
15100 if(!this.width && this.resizable){
15101 this.setSize(this.wrap.getSize());
15103 if (this.resizeEl) {
15104 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15105 // should trigger onReize..
15111 onResize : function(w, h)
15113 Roo.log('resize: ' +w + ',' + h );
15114 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15118 if(this.inputEl() ){
15119 if(typeof w == 'number'){
15120 var aw = w - this.wrap.getFrameWidth('lr');
15121 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15124 if(typeof h == 'number'){
15125 var tbh = -11; // fixme it needs to tool bar size!
15126 for (var i =0; i < this.toolbars.length;i++) {
15127 // fixme - ask toolbars for heights?
15128 tbh += this.toolbars[i].el.getHeight();
15129 //if (this.toolbars[i].footer) {
15130 // tbh += this.toolbars[i].footer.el.getHeight();
15138 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15139 ah -= 5; // knock a few pixes off for look..
15140 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15144 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15145 this.editorcore.onResize(ew,eh);
15150 * Toggles the editor between standard and source edit mode.
15151 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15153 toggleSourceEdit : function(sourceEditMode)
15155 this.editorcore.toggleSourceEdit(sourceEditMode);
15157 if(this.editorcore.sourceEditMode){
15158 Roo.log('editor - showing textarea');
15161 // Roo.log(this.syncValue());
15163 this.inputEl().removeClass('hide');
15164 this.inputEl().dom.removeAttribute('tabIndex');
15165 this.inputEl().focus();
15167 Roo.log('editor - hiding textarea');
15169 // Roo.log(this.pushValue());
15172 this.inputEl().addClass('hide');
15173 this.inputEl().dom.setAttribute('tabIndex', -1);
15174 //this.deferFocus();
15177 if(this.resizable){
15178 this.setSize(this.wrap.getSize());
15181 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15184 // private (for BoxComponent)
15185 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15187 // private (for BoxComponent)
15188 getResizeEl : function(){
15192 // private (for BoxComponent)
15193 getPositionEl : function(){
15198 initEvents : function(){
15199 this.originalValue = this.getValue();
15203 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15206 // markInvalid : Roo.emptyFn,
15208 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15211 // clearInvalid : Roo.emptyFn,
15213 setValue : function(v){
15214 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15215 this.editorcore.pushValue();
15220 deferFocus : function(){
15221 this.focus.defer(10, this);
15225 focus : function(){
15226 this.editorcore.focus();
15232 onDestroy : function(){
15238 for (var i =0; i < this.toolbars.length;i++) {
15239 // fixme - ask toolbars for heights?
15240 this.toolbars[i].onDestroy();
15243 this.wrap.dom.innerHTML = '';
15244 this.wrap.remove();
15249 onFirstFocus : function(){
15250 //Roo.log("onFirstFocus");
15251 this.editorcore.onFirstFocus();
15252 for (var i =0; i < this.toolbars.length;i++) {
15253 this.toolbars[i].onFirstFocus();
15259 syncValue : function()
15261 this.editorcore.syncValue();
15264 pushValue : function()
15266 this.editorcore.pushValue();
15270 // hide stuff that is not compatible
15284 * @event specialkey
15288 * @cfg {String} fieldClass @hide
15291 * @cfg {String} focusClass @hide
15294 * @cfg {String} autoCreate @hide
15297 * @cfg {String} inputType @hide
15300 * @cfg {String} invalidClass @hide
15303 * @cfg {String} invalidText @hide
15306 * @cfg {String} msgFx @hide
15309 * @cfg {String} validateOnBlur @hide
15320 * @class Roo.bootstrap.HtmlEditorToolbar1
15325 new Roo.bootstrap.HtmlEditor({
15328 new Roo.bootstrap.HtmlEditorToolbar1({
15329 disable : { fonts: 1 , format: 1, ..., ... , ...],
15335 * @cfg {Object} disable List of elements to disable..
15336 * @cfg {Array} btns List of additional buttons.
15340 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
15343 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
15346 Roo.apply(this, config);
15348 // default disabled, based on 'good practice'..
15349 this.disable = this.disable || {};
15350 Roo.applyIf(this.disable, {
15353 specialElements : true
15355 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
15357 this.editor = config.editor;
15358 this.editorcore = config.editor.editorcore;
15360 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
15362 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
15363 // dont call parent... till later.
15365 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
15371 editorcore : false,
15376 "h1","h2","h3","h4","h5","h6",
15378 "abbr", "acronym", "address", "cite", "samp", "var",
15382 onRender : function(ct, position)
15384 // Roo.log("Call onRender: " + this.xtype);
15386 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
15388 this.el.dom.style.marginBottom = '0';
15390 var editorcore = this.editorcore;
15391 var editor= this.editor;
15394 var btn = function(id,cmd , toggle, handler){
15396 var event = toggle ? 'toggle' : 'click';
15401 xns: Roo.bootstrap,
15404 enableToggle:toggle !== false,
15406 pressed : toggle ? false : null,
15409 a.listeners[toggle ? 'toggle' : 'click'] = function() {
15410 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
15419 xns: Roo.bootstrap,
15420 glyphicon : 'font',
15424 xns: Roo.bootstrap,
15428 Roo.each(this.formats, function(f) {
15429 style.menu.items.push({
15431 xns: Roo.bootstrap,
15432 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
15437 editorcore.insertTag(this.tagname);
15444 children.push(style);
15447 btn('bold',false,true);
15448 btn('italic',false,true);
15449 btn('align-left', 'justifyleft',true);
15450 btn('align-center', 'justifycenter',true);
15451 btn('align-right' , 'justifyright',true);
15452 btn('link', false, false, function(btn) {
15453 //Roo.log("create link?");
15454 var url = prompt(this.createLinkText, this.defaultLinkValue);
15455 if(url && url != 'http:/'+'/'){
15456 this.editorcore.relayCmd('createlink', url);
15459 btn('list','insertunorderedlist',true);
15460 btn('pencil', false,true, function(btn){
15463 this.toggleSourceEdit(btn.pressed);
15469 xns: Roo.bootstrap,
15474 xns: Roo.bootstrap,
15479 cog.menu.items.push({
15481 xns: Roo.bootstrap,
15482 html : Clean styles,
15487 editorcore.insertTag(this.tagname);
15496 this.xtype = 'Navbar';
15498 for(var i=0;i< children.length;i++) {
15500 this.buttons.add(this.addxtypeChild(children[i]));
15504 editor.on('editorevent', this.updateToolbar, this);
15506 onBtnClick : function(id)
15508 this.editorcore.relayCmd(id);
15509 this.editorcore.focus();
15513 * Protected method that will not generally be called directly. It triggers
15514 * a toolbar update by reading the markup state of the current selection in the editor.
15516 updateToolbar: function(){
15518 if(!this.editorcore.activated){
15519 this.editor.onFirstFocus(); // is this neeed?
15523 var btns = this.buttons;
15524 var doc = this.editorcore.doc;
15525 btns.get('bold').setActive(doc.queryCommandState('bold'));
15526 btns.get('italic').setActive(doc.queryCommandState('italic'));
15527 //btns.get('underline').setActive(doc.queryCommandState('underline'));
15529 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
15530 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
15531 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
15533 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
15534 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
15537 var ans = this.editorcore.getAllAncestors();
15538 if (this.formatCombo) {
15541 var store = this.formatCombo.store;
15542 this.formatCombo.setValue("");
15543 for (var i =0; i < ans.length;i++) {
15544 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
15546 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
15554 // hides menus... - so this cant be on a menu...
15555 Roo.bootstrap.MenuMgr.hideAll();
15557 Roo.bootstrap.MenuMgr.hideAll();
15558 //this.editorsyncValue();
15560 onFirstFocus: function() {
15561 this.buttons.each(function(item){
15565 toggleSourceEdit : function(sourceEditMode){
15568 if(sourceEditMode){
15569 Roo.log("disabling buttons");
15570 this.buttons.each( function(item){
15571 if(item.cmd != 'pencil'){
15577 Roo.log("enabling buttons");
15578 if(this.editorcore.initialized){
15579 this.buttons.each( function(item){
15585 Roo.log("calling toggole on editor");
15586 // tell the editor that it's been pressed..
15587 this.editor.toggleSourceEdit(sourceEditMode);
15597 * @class Roo.bootstrap.Table.AbstractSelectionModel
15598 * @extends Roo.util.Observable
15599 * Abstract base class for grid SelectionModels. It provides the interface that should be
15600 * implemented by descendant classes. This class should not be directly instantiated.
15603 Roo.bootstrap.Table.AbstractSelectionModel = function(){
15604 this.locked = false;
15605 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
15609 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
15610 /** @ignore Called by the grid automatically. Do not call directly. */
15611 init : function(grid){
15617 * Locks the selections.
15620 this.locked = true;
15624 * Unlocks the selections.
15626 unlock : function(){
15627 this.locked = false;
15631 * Returns true if the selections are locked.
15632 * @return {Boolean}
15634 isLocked : function(){
15635 return this.locked;
15639 * @class Roo.bootstrap.Table.ColumnModel
15640 * @extends Roo.util.Observable
15641 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15642 * the columns in the table.
15645 * @param {Object} config An Array of column config objects. See this class's
15646 * config objects for details.
15648 Roo.bootstrap.Table.ColumnModel = function(config){
15650 * The config passed into the constructor
15652 this.config = config;
15655 // if no id, create one
15656 // if the column does not have a dataIndex mapping,
15657 // map it to the order it is in the config
15658 for(var i = 0, len = config.length; i < len; i++){
15660 if(typeof c.dataIndex == "undefined"){
15663 if(typeof c.renderer == "string"){
15664 c.renderer = Roo.util.Format[c.renderer];
15666 if(typeof c.id == "undefined"){
15669 // if(c.editor && c.editor.xtype){
15670 // c.editor = Roo.factory(c.editor, Roo.grid);
15672 // if(c.editor && c.editor.isFormField){
15673 // c.editor = new Roo.grid.GridEditor(c.editor);
15676 this.lookup[c.id] = c;
15680 * The width of columns which have no width specified (defaults to 100)
15683 this.defaultWidth = 100;
15686 * Default sortable of columns which have no sortable specified (defaults to false)
15689 this.defaultSortable = false;
15693 * @event widthchange
15694 * Fires when the width of a column changes.
15695 * @param {ColumnModel} this
15696 * @param {Number} columnIndex The column index
15697 * @param {Number} newWidth The new width
15699 "widthchange": true,
15701 * @event headerchange
15702 * Fires when the text of a header changes.
15703 * @param {ColumnModel} this
15704 * @param {Number} columnIndex The column index
15705 * @param {Number} newText The new header text
15707 "headerchange": true,
15709 * @event hiddenchange
15710 * Fires when a column is hidden or "unhidden".
15711 * @param {ColumnModel} this
15712 * @param {Number} columnIndex The column index
15713 * @param {Boolean} hidden true if hidden, false otherwise
15715 "hiddenchange": true,
15717 * @event columnmoved
15718 * Fires when a column is moved.
15719 * @param {ColumnModel} this
15720 * @param {Number} oldIndex
15721 * @param {Number} newIndex
15723 "columnmoved" : true,
15725 * @event columlockchange
15726 * Fires when a column's locked state is changed
15727 * @param {ColumnModel} this
15728 * @param {Number} colIndex
15729 * @param {Boolean} locked true if locked
15731 "columnlockchange" : true
15733 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15735 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15737 * @cfg {String} header The header text to display in the Grid view.
15740 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15741 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15742 * specified, the column's index is used as an index into the Record's data Array.
15745 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15746 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15749 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15750 * Defaults to the value of the {@link #defaultSortable} property.
15751 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
15754 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
15757 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
15760 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
15763 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
15766 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
15767 * given the cell's data value. See {@link #setRenderer}. If not specified, the
15768 * default renderer uses the raw data value.
15771 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
15775 * Returns the id of the column at the specified index.
15776 * @param {Number} index The column index
15777 * @return {String} the id
15779 getColumnId : function(index){
15780 return this.config[index].id;
15784 * Returns the column for a specified id.
15785 * @param {String} id The column id
15786 * @return {Object} the column
15788 getColumnById : function(id){
15789 return this.lookup[id];
15794 * Returns the column for a specified dataIndex.
15795 * @param {String} dataIndex The column dataIndex
15796 * @return {Object|Boolean} the column or false if not found
15798 getColumnByDataIndex: function(dataIndex){
15799 var index = this.findColumnIndex(dataIndex);
15800 return index > -1 ? this.config[index] : false;
15804 * Returns the index for a specified column id.
15805 * @param {String} id The column id
15806 * @return {Number} the index, or -1 if not found
15808 getIndexById : function(id){
15809 for(var i = 0, len = this.config.length; i < len; i++){
15810 if(this.config[i].id == id){
15818 * Returns the index for a specified column dataIndex.
15819 * @param {String} dataIndex The column dataIndex
15820 * @return {Number} the index, or -1 if not found
15823 findColumnIndex : function(dataIndex){
15824 for(var i = 0, len = this.config.length; i < len; i++){
15825 if(this.config[i].dataIndex == dataIndex){
15833 moveColumn : function(oldIndex, newIndex){
15834 var c = this.config[oldIndex];
15835 this.config.splice(oldIndex, 1);
15836 this.config.splice(newIndex, 0, c);
15837 this.dataMap = null;
15838 this.fireEvent("columnmoved", this, oldIndex, newIndex);
15841 isLocked : function(colIndex){
15842 return this.config[colIndex].locked === true;
15845 setLocked : function(colIndex, value, suppressEvent){
15846 if(this.isLocked(colIndex) == value){
15849 this.config[colIndex].locked = value;
15850 if(!suppressEvent){
15851 this.fireEvent("columnlockchange", this, colIndex, value);
15855 getTotalLockedWidth : function(){
15856 var totalWidth = 0;
15857 for(var i = 0; i < this.config.length; i++){
15858 if(this.isLocked(i) && !this.isHidden(i)){
15859 this.totalWidth += this.getColumnWidth(i);
15865 getLockedCount : function(){
15866 for(var i = 0, len = this.config.length; i < len; i++){
15867 if(!this.isLocked(i)){
15874 * Returns the number of columns.
15877 getColumnCount : function(visibleOnly){
15878 if(visibleOnly === true){
15880 for(var i = 0, len = this.config.length; i < len; i++){
15881 if(!this.isHidden(i)){
15887 return this.config.length;
15891 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15892 * @param {Function} fn
15893 * @param {Object} scope (optional)
15894 * @return {Array} result
15896 getColumnsBy : function(fn, scope){
15898 for(var i = 0, len = this.config.length; i < len; i++){
15899 var c = this.config[i];
15900 if(fn.call(scope||this, c, i) === true){
15908 * Returns true if the specified column is sortable.
15909 * @param {Number} col The column index
15910 * @return {Boolean}
15912 isSortable : function(col){
15913 if(typeof this.config[col].sortable == "undefined"){
15914 return this.defaultSortable;
15916 return this.config[col].sortable;
15920 * Returns the rendering (formatting) function defined for the column.
15921 * @param {Number} col The column index.
15922 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15924 getRenderer : function(col){
15925 if(!this.config[col].renderer){
15926 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15928 return this.config[col].renderer;
15932 * Sets the rendering (formatting) function for a column.
15933 * @param {Number} col The column index
15934 * @param {Function} fn The function to use to process the cell's raw data
15935 * to return HTML markup for the grid view. The render function is called with
15936 * the following parameters:<ul>
15937 * <li>Data value.</li>
15938 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15939 * <li>css A CSS style string to apply to the table cell.</li>
15940 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15941 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15942 * <li>Row index</li>
15943 * <li>Column index</li>
15944 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15946 setRenderer : function(col, fn){
15947 this.config[col].renderer = fn;
15951 * Returns the width for the specified column.
15952 * @param {Number} col The column index
15955 getColumnWidth : function(col){
15956 return this.config[col].width * 1 || this.defaultWidth;
15960 * Sets the width for a column.
15961 * @param {Number} col The column index
15962 * @param {Number} width The new width
15964 setColumnWidth : function(col, width, suppressEvent){
15965 this.config[col].width = width;
15966 this.totalWidth = null;
15967 if(!suppressEvent){
15968 this.fireEvent("widthchange", this, col, width);
15973 * Returns the total width of all columns.
15974 * @param {Boolean} includeHidden True to include hidden column widths
15977 getTotalWidth : function(includeHidden){
15978 if(!this.totalWidth){
15979 this.totalWidth = 0;
15980 for(var i = 0, len = this.config.length; i < len; i++){
15981 if(includeHidden || !this.isHidden(i)){
15982 this.totalWidth += this.getColumnWidth(i);
15986 return this.totalWidth;
15990 * Returns the header for the specified column.
15991 * @param {Number} col The column index
15994 getColumnHeader : function(col){
15995 return this.config[col].header;
15999 * Sets the header for a column.
16000 * @param {Number} col The column index
16001 * @param {String} header The new header
16003 setColumnHeader : function(col, header){
16004 this.config[col].header = header;
16005 this.fireEvent("headerchange", this, col, header);
16009 * Returns the tooltip for the specified column.
16010 * @param {Number} col The column index
16013 getColumnTooltip : function(col){
16014 return this.config[col].tooltip;
16017 * Sets the tooltip for a column.
16018 * @param {Number} col The column index
16019 * @param {String} tooltip The new tooltip
16021 setColumnTooltip : function(col, tooltip){
16022 this.config[col].tooltip = tooltip;
16026 * Returns the dataIndex for the specified column.
16027 * @param {Number} col The column index
16030 getDataIndex : function(col){
16031 return this.config[col].dataIndex;
16035 * Sets the dataIndex for a column.
16036 * @param {Number} col The column index
16037 * @param {Number} dataIndex The new dataIndex
16039 setDataIndex : function(col, dataIndex){
16040 this.config[col].dataIndex = dataIndex;
16046 * Returns true if the cell is editable.
16047 * @param {Number} colIndex The column index
16048 * @param {Number} rowIndex The row index
16049 * @return {Boolean}
16051 isCellEditable : function(colIndex, rowIndex){
16052 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16056 * Returns the editor defined for the cell/column.
16057 * return false or null to disable editing.
16058 * @param {Number} colIndex The column index
16059 * @param {Number} rowIndex The row index
16062 getCellEditor : function(colIndex, rowIndex){
16063 return this.config[colIndex].editor;
16067 * Sets if a column is editable.
16068 * @param {Number} col The column index
16069 * @param {Boolean} editable True if the column is editable
16071 setEditable : function(col, editable){
16072 this.config[col].editable = editable;
16077 * Returns true if the column is hidden.
16078 * @param {Number} colIndex The column index
16079 * @return {Boolean}
16081 isHidden : function(colIndex){
16082 return this.config[colIndex].hidden;
16087 * Returns true if the column width cannot be changed
16089 isFixed : function(colIndex){
16090 return this.config[colIndex].fixed;
16094 * Returns true if the column can be resized
16095 * @return {Boolean}
16097 isResizable : function(colIndex){
16098 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16101 * Sets if a column is hidden.
16102 * @param {Number} colIndex The column index
16103 * @param {Boolean} hidden True if the column is hidden
16105 setHidden : function(colIndex, hidden){
16106 this.config[colIndex].hidden = hidden;
16107 this.totalWidth = null;
16108 this.fireEvent("hiddenchange", this, colIndex, hidden);
16112 * Sets the editor for a column.
16113 * @param {Number} col The column index
16114 * @param {Object} editor The editor object
16116 setEditor : function(col, editor){
16117 this.config[col].editor = editor;
16121 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16122 if(typeof value == "string" && value.length < 1){
16128 // Alias for backwards compatibility
16129 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16132 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16133 * @class Roo.bootstrap.Table.RowSelectionModel
16134 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16135 * It supports multiple selections and keyboard selection/navigation.
16137 * @param {Object} config
16140 Roo.bootstrap.Table.RowSelectionModel = function(config){
16141 Roo.apply(this, config);
16142 this.selections = new Roo.util.MixedCollection(false, function(o){
16147 this.lastActive = false;
16151 * @event selectionchange
16152 * Fires when the selection changes
16153 * @param {SelectionModel} this
16155 "selectionchange" : true,
16157 * @event afterselectionchange
16158 * Fires after the selection changes (eg. by key press or clicking)
16159 * @param {SelectionModel} this
16161 "afterselectionchange" : true,
16163 * @event beforerowselect
16164 * Fires when a row is selected being selected, return false to cancel.
16165 * @param {SelectionModel} this
16166 * @param {Number} rowIndex The selected index
16167 * @param {Boolean} keepExisting False if other selections will be cleared
16169 "beforerowselect" : true,
16172 * Fires when a row is selected.
16173 * @param {SelectionModel} this
16174 * @param {Number} rowIndex The selected index
16175 * @param {Roo.data.Record} r The record
16177 "rowselect" : true,
16179 * @event rowdeselect
16180 * Fires when a row is deselected.
16181 * @param {SelectionModel} this
16182 * @param {Number} rowIndex The selected index
16184 "rowdeselect" : true
16186 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16187 this.locked = false;
16190 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16192 * @cfg {Boolean} singleSelect
16193 * True to allow selection of only one row at a time (defaults to false)
16195 singleSelect : false,
16198 initEvents : function(){
16200 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16201 this.grid.on("mousedown", this.handleMouseDown, this);
16202 }else{ // allow click to work like normal
16203 this.grid.on("rowclick", this.handleDragableRowClick, this);
16206 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16207 "up" : function(e){
16209 this.selectPrevious(e.shiftKey);
16210 }else if(this.last !== false && this.lastActive !== false){
16211 var last = this.last;
16212 this.selectRange(this.last, this.lastActive-1);
16213 this.grid.getView().focusRow(this.lastActive);
16214 if(last !== false){
16218 this.selectFirstRow();
16220 this.fireEvent("afterselectionchange", this);
16222 "down" : function(e){
16224 this.selectNext(e.shiftKey);
16225 }else if(this.last !== false && this.lastActive !== false){
16226 var last = this.last;
16227 this.selectRange(this.last, this.lastActive+1);
16228 this.grid.getView().focusRow(this.lastActive);
16229 if(last !== false){
16233 this.selectFirstRow();
16235 this.fireEvent("afterselectionchange", this);
16240 var view = this.grid.view;
16241 view.on("refresh", this.onRefresh, this);
16242 view.on("rowupdated", this.onRowUpdated, this);
16243 view.on("rowremoved", this.onRemove, this);
16247 onRefresh : function(){
16248 var ds = this.grid.dataSource, i, v = this.grid.view;
16249 var s = this.selections;
16250 s.each(function(r){
16251 if((i = ds.indexOfId(r.id)) != -1){
16260 onRemove : function(v, index, r){
16261 this.selections.remove(r);
16265 onRowUpdated : function(v, index, r){
16266 if(this.isSelected(r)){
16267 v.onRowSelect(index);
16273 * @param {Array} records The records to select
16274 * @param {Boolean} keepExisting (optional) True to keep existing selections
16276 selectRecords : function(records, keepExisting){
16278 this.clearSelections();
16280 var ds = this.grid.dataSource;
16281 for(var i = 0, len = records.length; i < len; i++){
16282 this.selectRow(ds.indexOf(records[i]), true);
16287 * Gets the number of selected rows.
16290 getCount : function(){
16291 return this.selections.length;
16295 * Selects the first row in the grid.
16297 selectFirstRow : function(){
16302 * Select the last row.
16303 * @param {Boolean} keepExisting (optional) True to keep existing selections
16305 selectLastRow : function(keepExisting){
16306 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
16310 * Selects the row immediately following the last selected row.
16311 * @param {Boolean} keepExisting (optional) True to keep existing selections
16313 selectNext : function(keepExisting){
16314 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
16315 this.selectRow(this.last+1, keepExisting);
16316 this.grid.getView().focusRow(this.last);
16321 * Selects the row that precedes the last selected row.
16322 * @param {Boolean} keepExisting (optional) True to keep existing selections
16324 selectPrevious : function(keepExisting){
16326 this.selectRow(this.last-1, keepExisting);
16327 this.grid.getView().focusRow(this.last);
16332 * Returns the selected records
16333 * @return {Array} Array of selected records
16335 getSelections : function(){
16336 return [].concat(this.selections.items);
16340 * Returns the first selected record.
16343 getSelected : function(){
16344 return this.selections.itemAt(0);
16349 * Clears all selections.
16351 clearSelections : function(fast){
16352 if(this.locked) return;
16354 var ds = this.grid.dataSource;
16355 var s = this.selections;
16356 s.each(function(r){
16357 this.deselectRow(ds.indexOfId(r.id));
16361 this.selections.clear();
16368 * Selects all rows.
16370 selectAll : function(){
16371 if(this.locked) return;
16372 this.selections.clear();
16373 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
16374 this.selectRow(i, true);
16379 * Returns True if there is a selection.
16380 * @return {Boolean}
16382 hasSelection : function(){
16383 return this.selections.length > 0;
16387 * Returns True if the specified row is selected.
16388 * @param {Number/Record} record The record or index of the record to check
16389 * @return {Boolean}
16391 isSelected : function(index){
16392 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
16393 return (r && this.selections.key(r.id) ? true : false);
16397 * Returns True if the specified record id is selected.
16398 * @param {String} id The id of record to check
16399 * @return {Boolean}
16401 isIdSelected : function(id){
16402 return (this.selections.key(id) ? true : false);
16406 handleMouseDown : function(e, t){
16407 var view = this.grid.getView(), rowIndex;
16408 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
16411 if(e.shiftKey && this.last !== false){
16412 var last = this.last;
16413 this.selectRange(last, rowIndex, e.ctrlKey);
16414 this.last = last; // reset the last
16415 view.focusRow(rowIndex);
16417 var isSelected = this.isSelected(rowIndex);
16418 if(e.button !== 0 && isSelected){
16419 view.focusRow(rowIndex);
16420 }else if(e.ctrlKey && isSelected){
16421 this.deselectRow(rowIndex);
16422 }else if(!isSelected){
16423 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
16424 view.focusRow(rowIndex);
16427 this.fireEvent("afterselectionchange", this);
16430 handleDragableRowClick : function(grid, rowIndex, e)
16432 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
16433 this.selectRow(rowIndex, false);
16434 grid.view.focusRow(rowIndex);
16435 this.fireEvent("afterselectionchange", this);
16440 * Selects multiple rows.
16441 * @param {Array} rows Array of the indexes of the row to select
16442 * @param {Boolean} keepExisting (optional) True to keep existing selections
16444 selectRows : function(rows, keepExisting){
16446 this.clearSelections();
16448 for(var i = 0, len = rows.length; i < len; i++){
16449 this.selectRow(rows[i], true);
16454 * Selects a range of rows. All rows in between startRow and endRow are also selected.
16455 * @param {Number} startRow The index of the first row in the range
16456 * @param {Number} endRow The index of the last row in the range
16457 * @param {Boolean} keepExisting (optional) True to retain existing selections
16459 selectRange : function(startRow, endRow, keepExisting){
16460 if(this.locked) return;
16462 this.clearSelections();
16464 if(startRow <= endRow){
16465 for(var i = startRow; i <= endRow; i++){
16466 this.selectRow(i, true);
16469 for(var i = startRow; i >= endRow; i--){
16470 this.selectRow(i, true);
16476 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
16477 * @param {Number} startRow The index of the first row in the range
16478 * @param {Number} endRow The index of the last row in the range
16480 deselectRange : function(startRow, endRow, preventViewNotify){
16481 if(this.locked) return;
16482 for(var i = startRow; i <= endRow; i++){
16483 this.deselectRow(i, preventViewNotify);
16489 * @param {Number} row The index of the row to select
16490 * @param {Boolean} keepExisting (optional) True to keep existing selections
16492 selectRow : function(index, keepExisting, preventViewNotify){
16493 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
16494 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
16495 if(!keepExisting || this.singleSelect){
16496 this.clearSelections();
16498 var r = this.grid.dataSource.getAt(index);
16499 this.selections.add(r);
16500 this.last = this.lastActive = index;
16501 if(!preventViewNotify){
16502 this.grid.getView().onRowSelect(index);
16504 this.fireEvent("rowselect", this, index, r);
16505 this.fireEvent("selectionchange", this);
16511 * @param {Number} row The index of the row to deselect
16513 deselectRow : function(index, preventViewNotify){
16514 if(this.locked) return;
16515 if(this.last == index){
16518 if(this.lastActive == index){
16519 this.lastActive = false;
16521 var r = this.grid.dataSource.getAt(index);
16522 this.selections.remove(r);
16523 if(!preventViewNotify){
16524 this.grid.getView().onRowDeselect(index);
16526 this.fireEvent("rowdeselect", this, index);
16527 this.fireEvent("selectionchange", this);
16531 restoreLast : function(){
16533 this.last = this._last;
16538 acceptsNav : function(row, col, cm){
16539 return !cm.isHidden(col) && cm.isCellEditable(col, row);
16543 onEditorKey : function(field, e){
16544 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
16549 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
16551 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
16553 }else if(k == e.ENTER && !e.ctrlKey){
16557 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
16559 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
16561 }else if(k == e.ESC){
16565 g.startEditing(newCell[0], newCell[1]);
16576 * @class Roo.bootstrap.MessageBar
16577 * @extends Roo.bootstrap.Component
16578 * Bootstrap MessageBar class
16579 * @cfg {String} html contents of the MessageBar
16580 * @cfg {String} weight (info | success | warning | danger) default info
16581 * @cfg {String} beforeClass insert the bar before the given class
16582 * @cfg {Boolean} closable (true | false) default false
16583 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
16586 * Create a new Element
16587 * @param {Object} config The config object
16590 Roo.bootstrap.MessageBar = function(config){
16591 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
16594 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
16600 beforeClass: 'bootstrap-sticky-wrap',
16602 getAutoCreate : function(){
16606 cls: 'alert alert-dismissable alert-' + this.weight,
16611 html: this.html || ''
16617 cfg.cls += ' alert-messages-fixed';
16631 onRender : function(ct, position)
16633 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16636 var cfg = Roo.apply({}, this.getAutoCreate());
16640 cfg.cls += ' ' + this.cls;
16643 cfg.style = this.style;
16645 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16647 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16650 this.el.select('>button.close').on('click', this.hide, this);
16656 if (!this.rendered) {
16662 this.fireEvent('show', this);
16668 if (!this.rendered) {
16674 this.fireEvent('hide', this);
16677 update : function()
16679 // var e = this.el.dom.firstChild;
16681 // if(this.closable){
16682 // e = e.nextSibling;
16685 // e.data = this.html || '';
16687 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';