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
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
104 cfg.id = this.id || Roo.id();
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
349 this.el.removeClass('hidden');
352 * Hide a component - adds 'hidden' class
356 if (!this.el.hasClass('hidden')) {
357 this.el.addClass('hidden');
371 * @class Roo.bootstrap.Body
372 * @extends Roo.bootstrap.Component
373 * Bootstrap Body class
377 * @param {Object} config The config object
380 Roo.bootstrap.Body = function(config){
381 Roo.bootstrap.Body.superclass.constructor.call(this, config);
382 this.el = Roo.get(document.body);
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
388 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
393 onRender : function(ct, position)
395 /* Roo.log("Roo.bootstrap.Body - onRender");
396 if (this.cls && this.cls.length) {
397 Roo.get(document.body).addClass(this.cls);
417 * @class Roo.bootstrap.ButtonGroup
418 * @extends Roo.bootstrap.Component
419 * Bootstrap ButtonGroup class
420 * @cfg {String} size lg | sm | xs (default empty normal)
421 * @cfg {String} align vertical | justified (default none)
422 * @cfg {String} direction up | down (default down)
423 * @cfg {Boolean} toolbar false | true
424 * @cfg {Boolean} btn true | false
429 * @param {Object} config The config object
432 Roo.bootstrap.ButtonGroup = function(config){
433 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
436 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
444 getAutoCreate : function(){
450 cfg.html = this.html || cfg.html;
461 if (['vertical','justified'].indexOf(this.align)!==-1) {
462 cfg.cls = 'btn-group-' + this.align;
464 if (this.align == 'justified') {
465 console.log(this.items);
469 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
470 cfg.cls += ' btn-group-' + this.size;
473 if (this.direction == 'up') {
474 cfg.cls += ' dropup' ;
490 * @class Roo.bootstrap.Button
491 * @extends Roo.bootstrap.Component
492 * Bootstrap Button class
493 * @cfg {String} html The button content
494 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
495 * @cfg {String} size ( lg | sm | xs)
496 * @cfg {String} tag ( a | input | submit)
497 * @cfg {String} href empty or href
498 * @cfg {Boolean} disabled default false;
499 * @cfg {Boolean} isClose default false;
500 * @cfg {String} glyphicon (| 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)
501 * @cfg {String} badge text for badge
502 * @cfg {String} theme default
503 * @cfg {Boolean} inverse
504 * @cfg {Boolean} toggle
505 * @cfg {String} ontext text for on toggle state
506 * @cfg {String} offtext text for off toggle state
507 * @cfg {Boolean} defaulton
508 * @cfg {Boolean} preventDefault default true
509 * @cfg {Boolean} removeClass remove the standard class..
510 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
513 * Create a new button
514 * @param {Object} config The config object
518 Roo.bootstrap.Button = function(config){
519 Roo.bootstrap.Button.superclass.constructor.call(this, config);
524 * When a butotn is pressed
525 * @param {Roo.bootstrap.Button} this
526 * @param {Roo.EventObject} e
531 * After the button has been toggles
532 * @param {Roo.EventObject} e
533 * @param {boolean} pressed (also available as button.pressed)
539 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
557 preventDefault: true,
566 getAutoCreate : function(){
574 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
575 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
580 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
582 if (this.toggle == true) {
585 cls: 'slider-frame roo-button',
590 'data-off-text':'OFF',
591 cls: 'slider-button',
597 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
598 cfg.cls += ' '+this.weight;
607 cfg["aria-hidden"] = true;
609 cfg.html = "×";
615 if (this.theme==='default') {
616 cfg.cls = 'btn roo-button';
618 //if (this.parentType != 'Navbar') {
619 this.weight = this.weight.length ? this.weight : 'default';
621 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
623 cfg.cls += ' btn-' + this.weight;
625 } else if (this.theme==='glow') {
628 cfg.cls = 'btn-glow roo-button';
630 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
632 cfg.cls += ' ' + this.weight;
638 this.cls += ' inverse';
643 cfg.cls += ' active';
647 cfg.disabled = 'disabled';
651 Roo.log('changing to ul' );
653 this.glyphicon = 'caret';
656 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
658 //gsRoo.log(this.parentType);
659 if (this.parentType === 'Navbar' && !this.parent().bar) {
660 Roo.log('changing to li?');
669 href : this.href || '#'
672 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
673 cfg.cls += ' dropdown';
680 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
682 if (this.glyphicon) {
683 cfg.html = ' ' + cfg.html;
688 cls: 'glyphicon glyphicon-' + this.glyphicon
698 // cfg.cls='btn roo-button';
702 var value = cfg.html;
707 cls: 'glyphicon glyphicon-' + this.glyphicon,
726 cfg.cls += ' dropdown';
727 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
730 if (cfg.tag !== 'a' && this.href !== '') {
731 throw "Tag must be a to set href.";
732 } else if (this.href.length > 0) {
733 cfg.href = this.href;
736 if(this.removeClass){
741 cfg.target = this.target;
746 initEvents: function() {
747 // Roo.log('init events?');
748 // Roo.log(this.el.dom);
751 if (typeof (this.menu) != 'undefined') {
752 this.menu.parentType = this.xtype;
753 this.menu.triggerEl = this.el;
754 this.addxtype(Roo.apply({}, this.menu));
758 if (this.el.hasClass('roo-button')) {
759 this.el.on('click', this.onClick, this);
761 this.el.select('.roo-button').on('click', this.onClick, this);
764 if(this.removeClass){
765 this.el.on('click', this.onClick, this);
768 this.el.enableDisplayMode();
771 onClick : function(e)
778 Roo.log('button on click ');
779 if(this.preventDefault){
782 if (this.pressed === true || this.pressed === false) {
783 this.pressed = !this.pressed;
784 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
785 this.fireEvent('toggle', this, e, this.pressed);
789 this.fireEvent('click', this, e);
793 * Enables this button
797 this.disabled = false;
798 this.el.removeClass('disabled');
802 * Disable this button
806 this.disabled = true;
807 this.el.addClass('disabled');
810 * sets the active state on/off,
811 * @param {Boolean} state (optional) Force a particular state
813 setActive : function(v) {
815 this.el[v ? 'addClass' : 'removeClass']('active');
818 * toggles the current active state
820 toggleActive : function()
822 var active = this.el.hasClass('active');
823 this.setActive(!active);
827 setText : function(str)
829 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
833 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
856 * @class Roo.bootstrap.Column
857 * @extends Roo.bootstrap.Component
858 * Bootstrap Column class
859 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
860 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
861 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
862 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
863 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
864 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
865 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
866 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
869 * @cfg {Boolean} hidden (true|false) hide the element
870 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
871 * @cfg {String} fa (ban|check|...) font awesome icon
872 * @cfg {Number} fasize (1|2|....) font awsome size
874 * @cfg {String} icon (info-sign|check|...) glyphicon name
876 * @cfg {String} html content of column.
879 * Create a new Column
880 * @param {Object} config The config object
883 Roo.bootstrap.Column = function(config){
884 Roo.bootstrap.Column.superclass.constructor.call(this, config);
887 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
905 getAutoCreate : function(){
906 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
914 ['xs','sm','md','lg'].map(function(size){
915 //Roo.log( size + ':' + settings[size]);
917 if (settings[size+'off'] !== false) {
918 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
921 if (settings[size] === false) {
924 Roo.log(settings[size]);
925 if (!settings[size]) { // 0 = hidden
926 cfg.cls += ' hidden-' + size;
929 cfg.cls += ' col-' + size + '-' + settings[size];
934 cfg.cls += ' hidden';
937 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
938 cfg.cls +=' alert alert-' + this.alert;
942 if (this.html.length) {
943 cfg.html = this.html;
947 if (this.fasize > 1) {
948 fasize = ' fa-' + this.fasize + 'x';
950 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
955 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
974 * @class Roo.bootstrap.Container
975 * @extends Roo.bootstrap.Component
976 * Bootstrap Container class
977 * @cfg {Boolean} jumbotron is it a jumbotron element
978 * @cfg {String} html content of element
979 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
980 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
981 * @cfg {String} header content of header (for panel)
982 * @cfg {String} footer content of footer (for panel)
983 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
984 * @cfg {String} tag (header|aside|section) type of HTML tag.
985 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
986 * @cfg {String} fa (ban|check|...) font awesome icon
987 * @cfg {String} icon (info-sign|check|...) glyphicon name
988 * @cfg {Boolean} hidden (true|false) hide the element
992 * Create a new Container
993 * @param {Object} config The config object
996 Roo.bootstrap.Container = function(config){
997 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1000 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1014 getChildContainer : function() {
1020 if (this.panel.length) {
1021 return this.el.select('.panel-body',true).first();
1028 getAutoCreate : function(){
1031 tag : this.tag || 'div',
1035 if (this.jumbotron) {
1036 cfg.cls = 'jumbotron';
1041 // - this is applied by the parent..
1043 // cfg.cls = this.cls + '';
1046 if (this.sticky.length) {
1048 var bd = Roo.get(document.body);
1049 if (!bd.hasClass('bootstrap-sticky')) {
1050 bd.addClass('bootstrap-sticky');
1051 Roo.select('html',true).setStyle('height', '100%');
1054 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1058 if (this.well.length) {
1059 switch (this.well) {
1062 cfg.cls +=' well well-' +this.well;
1071 cfg.cls += ' hidden';
1075 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1076 cfg.cls +=' alert alert-' + this.alert;
1081 if (this.panel.length) {
1082 cfg.cls += ' panel panel-' + this.panel;
1084 if (this.header.length) {
1087 cls : 'panel-heading',
1090 cls : 'panel-title',
1103 if (this.footer.length) {
1105 cls : 'panel-footer',
1114 body.html = this.html || cfg.html;
1115 // prefix with the icons..
1117 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1120 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1125 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1126 cfg.cls = 'container';
1132 titleEl : function()
1134 if(!this.el || !this.panel.length || !this.header.length){
1138 return this.el.select('.panel-title',true).first();
1141 setTitle : function(v)
1143 var titleEl = this.titleEl();
1149 titleEl.dom.innerHTML = v;
1152 getTitle : function()
1155 var titleEl = this.titleEl();
1161 return titleEl.dom.innerHTML;
1177 * @class Roo.bootstrap.Img
1178 * @extends Roo.bootstrap.Component
1179 * Bootstrap Img class
1180 * @cfg {Boolean} imgResponsive false | true
1181 * @cfg {String} border rounded | circle | thumbnail
1182 * @cfg {String} src image source
1183 * @cfg {String} alt image alternative text
1184 * @cfg {String} href a tag href
1185 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1188 * Create a new Input
1189 * @param {Object} config The config object
1192 Roo.bootstrap.Img = function(config){
1193 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1199 * The img click event for the img.
1200 * @param {Roo.EventObject} e
1206 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1208 imgResponsive: true,
1214 getAutoCreate : function(){
1218 cls: (this.imgResponsive) ? 'img-responsive' : '',
1222 cfg.html = this.html || cfg.html;
1224 cfg.src = this.src || cfg.src;
1226 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1227 cfg.cls += ' img-' + this.border;
1244 a.target = this.target;
1250 return (this.href) ? a : cfg;
1253 initEvents: function() {
1256 this.el.on('click', this.onClick, this);
1260 onClick : function(e)
1262 Roo.log('img onclick');
1263 this.fireEvent('click', this, e);
1277 * @class Roo.bootstrap.Link
1278 * @extends Roo.bootstrap.Component
1279 * Bootstrap Link Class
1280 * @cfg {String} alt image alternative text
1281 * @cfg {String} href a tag href
1282 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1283 * @cfg {String} html the content of the link.
1284 * @cfg {String} anchor name for the anchor link
1286 * @cfg {Boolean} preventDefault (true | false) default false
1290 * Create a new Input
1291 * @param {Object} config The config object
1294 Roo.bootstrap.Link = function(config){
1295 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1301 * The img click event for the img.
1302 * @param {Roo.EventObject} e
1308 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1312 preventDefault: false,
1316 getAutoCreate : function()
1322 // anchor's do not require html/href...
1323 if (this.anchor === false) {
1324 cfg.html = this.html || 'html-missing';
1325 cfg.href = this.href || '#';
1327 cfg.name = this.anchor;
1328 if (this.html !== false) {
1329 cfg.html = this.html;
1331 if (this.href !== false) {
1332 cfg.href = this.href;
1336 if(this.alt !== false){
1341 if(this.target !== false) {
1342 cfg.target = this.target;
1348 initEvents: function() {
1350 if(!this.href || this.preventDefault){
1351 this.el.on('click', this.onClick, this);
1355 onClick : function(e)
1357 if(this.preventDefault){
1360 //Roo.log('img onclick');
1361 this.fireEvent('click', this, e);
1374 * @class Roo.bootstrap.Header
1375 * @extends Roo.bootstrap.Component
1376 * Bootstrap Header class
1377 * @cfg {String} html content of header
1378 * @cfg {Number} level (1|2|3|4|5|6) default 1
1381 * Create a new Header
1382 * @param {Object} config The config object
1386 Roo.bootstrap.Header = function(config){
1387 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1390 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1398 getAutoCreate : function(){
1403 tag: 'h' + (1 *this.level),
1404 html: this.html || ''
1416 * Ext JS Library 1.1.1
1417 * Copyright(c) 2006-2007, Ext JS, LLC.
1419 * Originally Released Under LGPL - original licence link has changed is not relivant.
1422 * <script type="text/javascript">
1426 * @class Roo.bootstrap.MenuMgr
1427 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1430 Roo.bootstrap.MenuMgr = function(){
1431 var menus, active, groups = {}, attached = false, lastShow = new Date();
1433 // private - called when first menu is created
1436 active = new Roo.util.MixedCollection();
1437 Roo.get(document).addKeyListener(27, function(){
1438 if(active.length > 0){
1446 if(active && active.length > 0){
1447 var c = active.clone();
1457 if(active.length < 1){
1458 Roo.get(document).un("mouseup", onMouseDown);
1466 var last = active.last();
1467 lastShow = new Date();
1470 Roo.get(document).on("mouseup", onMouseDown);
1475 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1476 m.parentMenu.activeChild = m;
1477 }else if(last && last.isVisible()){
1478 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1483 function onBeforeHide(m){
1485 m.activeChild.hide();
1487 if(m.autoHideTimer){
1488 clearTimeout(m.autoHideTimer);
1489 delete m.autoHideTimer;
1494 function onBeforeShow(m){
1495 var pm = m.parentMenu;
1496 if(!pm && !m.allowOtherMenus){
1498 }else if(pm && pm.activeChild && active != m){
1499 pm.activeChild.hide();
1504 function onMouseDown(e){
1505 Roo.log("on MouseDown");
1506 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1514 function onBeforeCheck(mi, state){
1516 var g = groups[mi.group];
1517 for(var i = 0, l = g.length; i < l; i++){
1519 g[i].setChecked(false);
1528 * Hides all menus that are currently visible
1530 hideAll : function(){
1535 register : function(menu){
1539 menus[menu.id] = menu;
1540 menu.on("beforehide", onBeforeHide);
1541 menu.on("hide", onHide);
1542 menu.on("beforeshow", onBeforeShow);
1543 menu.on("show", onShow);
1545 if(g && menu.events["checkchange"]){
1549 groups[g].push(menu);
1550 menu.on("checkchange", onCheck);
1555 * Returns a {@link Roo.menu.Menu} object
1556 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1557 * be used to generate and return a new Menu instance.
1559 get : function(menu){
1560 if(typeof menu == "string"){ // menu id
1562 }else if(menu.events){ // menu instance
1565 /*else if(typeof menu.length == 'number'){ // array of menu items?
1566 return new Roo.bootstrap.Menu({items:menu});
1567 }else{ // otherwise, must be a config
1568 return new Roo.bootstrap.Menu(menu);
1575 unregister : function(menu){
1576 delete menus[menu.id];
1577 menu.un("beforehide", onBeforeHide);
1578 menu.un("hide", onHide);
1579 menu.un("beforeshow", onBeforeShow);
1580 menu.un("show", onShow);
1582 if(g && menu.events["checkchange"]){
1583 groups[g].remove(menu);
1584 menu.un("checkchange", onCheck);
1589 registerCheckable : function(menuItem){
1590 var g = menuItem.group;
1595 groups[g].push(menuItem);
1596 menuItem.on("beforecheckchange", onBeforeCheck);
1601 unregisterCheckable : function(menuItem){
1602 var g = menuItem.group;
1604 groups[g].remove(menuItem);
1605 menuItem.un("beforecheckchange", onBeforeCheck);
1617 * @class Roo.bootstrap.Menu
1618 * @extends Roo.bootstrap.Component
1619 * Bootstrap Menu class - container for MenuItems
1620 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1624 * @param {Object} config The config object
1628 Roo.bootstrap.Menu = function(config){
1629 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1630 if (this.registerMenu) {
1631 Roo.bootstrap.MenuMgr.register(this);
1636 * Fires before this menu is displayed
1637 * @param {Roo.menu.Menu} this
1642 * Fires before this menu is hidden
1643 * @param {Roo.menu.Menu} this
1648 * Fires after this menu is displayed
1649 * @param {Roo.menu.Menu} this
1654 * Fires after this menu is hidden
1655 * @param {Roo.menu.Menu} this
1660 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1661 * @param {Roo.menu.Menu} this
1662 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1663 * @param {Roo.EventObject} e
1668 * Fires when the mouse is hovering over this menu
1669 * @param {Roo.menu.Menu} this
1670 * @param {Roo.EventObject} e
1671 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1676 * Fires when the mouse exits this menu
1677 * @param {Roo.menu.Menu} this
1678 * @param {Roo.EventObject} e
1679 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1684 * Fires when a menu item contained in this menu is clicked
1685 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1686 * @param {Roo.EventObject} e
1690 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1693 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1697 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1700 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1702 registerMenu : true,
1704 menuItems :false, // stores the menu items..
1710 getChildContainer : function() {
1714 getAutoCreate : function(){
1716 //if (['right'].indexOf(this.align)!==-1) {
1717 // cfg.cn[1].cls += ' pull-right'
1723 cls : 'dropdown-menu' ,
1724 style : 'z-index:1000'
1728 if (this.type === 'submenu') {
1729 cfg.cls = 'submenu active';
1731 if (this.type === 'treeview') {
1732 cfg.cls = 'treeview-menu';
1737 initEvents : function() {
1739 // Roo.log("ADD event");
1740 // Roo.log(this.triggerEl.dom);
1741 this.triggerEl.on('click', this.onTriggerPress, this);
1742 this.triggerEl.addClass('dropdown-toggle');
1743 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1745 this.el.on("mouseover", this.onMouseOver, this);
1746 this.el.on("mouseout", this.onMouseOut, this);
1750 findTargetItem : function(e){
1751 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1755 //Roo.log(t); Roo.log(t.id);
1757 //Roo.log(this.menuitems);
1758 return this.menuitems.get(t.id);
1760 //return this.items.get(t.menuItemId);
1765 onClick : function(e){
1766 Roo.log("menu.onClick");
1767 var t = this.findTargetItem(e);
1768 if(!t || t.isContainer){
1773 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1774 if(t == this.activeItem && t.shouldDeactivate(e)){
1775 this.activeItem.deactivate();
1776 delete this.activeItem;
1780 this.setActiveItem(t, true);
1788 Roo.log('pass click event');
1792 this.fireEvent("click", this, t, e);
1796 onMouseOver : function(e){
1797 var t = this.findTargetItem(e);
1800 // if(t.canActivate && !t.disabled){
1801 // this.setActiveItem(t, true);
1805 this.fireEvent("mouseover", this, e, t);
1807 isVisible : function(){
1808 return !this.hidden;
1810 onMouseOut : function(e){
1811 var t = this.findTargetItem(e);
1814 // if(t == this.activeItem && t.shouldDeactivate(e)){
1815 // this.activeItem.deactivate();
1816 // delete this.activeItem;
1819 this.fireEvent("mouseout", this, e, t);
1824 * Displays this menu relative to another element
1825 * @param {String/HTMLElement/Roo.Element} element The element to align to
1826 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1827 * the element (defaults to this.defaultAlign)
1828 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1830 show : function(el, pos, parentMenu){
1831 this.parentMenu = parentMenu;
1835 this.fireEvent("beforeshow", this);
1836 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1839 * Displays this menu at a specific xy position
1840 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1841 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1843 showAt : function(xy, parentMenu, /* private: */_e){
1844 this.parentMenu = parentMenu;
1849 this.fireEvent("beforeshow", this);
1850 //xy = this.el.adjustForConstraints(xy);
1854 this.hideMenuItems();
1855 this.hidden = false;
1856 this.triggerEl.addClass('open');
1858 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1859 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1864 this.fireEvent("show", this);
1870 this.doFocus.defer(50, this);
1874 doFocus : function(){
1876 this.focusEl.focus();
1881 * Hides this menu and optionally all parent menus
1882 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1884 hide : function(deep){
1886 this.hideMenuItems();
1887 if(this.el && this.isVisible()){
1888 this.fireEvent("beforehide", this);
1889 if(this.activeItem){
1890 this.activeItem.deactivate();
1891 this.activeItem = null;
1893 this.triggerEl.removeClass('open');;
1895 this.fireEvent("hide", this);
1897 if(deep === true && this.parentMenu){
1898 this.parentMenu.hide(true);
1902 onTriggerPress : function(e)
1905 Roo.log('trigger press');
1906 //Roo.log(e.getTarget());
1907 // Roo.log(this.triggerEl.dom);
1908 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1911 if (this.isVisible()) {
1915 this.show(this.triggerEl, false, false);
1924 hideMenuItems : function()
1926 //$(backdrop).remove()
1927 Roo.select('.open',true).each(function(aa) {
1929 aa.removeClass('open');
1930 //var parent = getParent($(this))
1931 //var relatedTarget = { relatedTarget: this }
1933 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1934 //if (e.isDefaultPrevented()) return
1935 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1938 addxtypeChild : function (tree, cntr) {
1939 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1941 this.menuitems.add(comp);
1962 * @class Roo.bootstrap.MenuItem
1963 * @extends Roo.bootstrap.Component
1964 * Bootstrap MenuItem class
1965 * @cfg {String} html the menu label
1966 * @cfg {String} href the link
1967 * @cfg {Boolean} preventDefault (true | false) default true
1968 * @cfg {Boolean} isContainer (true | false) default false
1972 * Create a new MenuItem
1973 * @param {Object} config The config object
1977 Roo.bootstrap.MenuItem = function(config){
1978 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1983 * The raw click event for the entire grid.
1984 * @param {Roo.bootstrap.MenuItem} this
1985 * @param {Roo.EventObject} e
1991 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1995 preventDefault: true,
1996 isContainer : false,
1998 getAutoCreate : function(){
2000 if(this.isContainer){
2003 cls: 'dropdown-menu-item'
2009 cls: 'dropdown-menu-item',
2018 if (this.parent().type == 'treeview') {
2019 cfg.cls = 'treeview-menu';
2022 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2023 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2027 initEvents: function() {
2029 //this.el.select('a').on('click', this.onClick, this);
2032 onClick : function(e)
2034 Roo.log('item on click ');
2035 //if(this.preventDefault){
2036 // e.preventDefault();
2038 //this.parent().hideMenuItems();
2040 this.fireEvent('click', this, e);
2059 * @class Roo.bootstrap.MenuSeparator
2060 * @extends Roo.bootstrap.Component
2061 * Bootstrap MenuSeparator class
2064 * Create a new MenuItem
2065 * @param {Object} config The config object
2069 Roo.bootstrap.MenuSeparator = function(config){
2070 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2073 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2075 getAutoCreate : function(){
2094 * @class Roo.bootstrap.Modal
2095 * @extends Roo.bootstrap.Component
2096 * Bootstrap Modal class
2097 * @cfg {String} title Title of dialog
2098 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2099 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2100 * @cfg {Boolean} specificTitle default false
2101 * @cfg {Array} buttons Array of buttons or standard button set..
2102 * @cfg {String} buttonPosition (left|right|center) default right
2103 * @cfg {Boolean} animate default true
2104 * @cfg {Boolean} allow_close default true
2107 * Create a new Modal Dialog
2108 * @param {Object} config The config object
2111 Roo.bootstrap.Modal = function(config){
2112 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2117 * The raw btnclick event for the button
2118 * @param {Roo.EventObject} e
2122 this.buttons = this.buttons || [];
2125 this.tmpl = Roo.factory(this.tmpl);
2130 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2132 title : 'test dialog',
2142 specificTitle: false,
2144 buttonPosition: 'right',
2158 onRender : function(ct, position)
2160 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2163 var cfg = Roo.apply({}, this.getAutoCreate());
2166 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2168 //if (!cfg.name.length) {
2172 cfg.cls += ' ' + this.cls;
2175 cfg.style = this.style;
2177 this.el = Roo.get(document.body).createChild(cfg, position);
2179 //var type = this.el.dom.type;
2184 if(this.tabIndex !== undefined){
2185 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2189 this.bodyEl = this.el.select('.modal-body',true).first();
2190 this.closeEl = this.el.select('.modal-header .close', true).first();
2191 this.footerEl = this.el.select('.modal-footer',true).first();
2192 this.titleEl = this.el.select('.modal-title',true).first();
2196 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2197 this.maskEl.enableDisplayMode("block");
2199 //this.el.addClass("x-dlg-modal");
2201 if (this.buttons.length) {
2202 Roo.each(this.buttons, function(bb) {
2203 b = Roo.apply({}, bb);
2204 b.xns = b.xns || Roo.bootstrap;
2205 b.xtype = b.xtype || 'Button';
2206 if (typeof(b.listeners) == 'undefined') {
2207 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2210 var btn = Roo.factory(b);
2212 btn.onRender(this.el.select('.modal-footer div').first());
2216 // render the children.
2219 if(typeof(this.items) != 'undefined'){
2220 var items = this.items;
2223 for(var i =0;i < items.length;i++) {
2224 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2228 this.items = nitems;
2230 // where are these used - they used to be body/close/footer
2234 //this.el.addClass([this.fieldClass, this.cls]);
2237 getAutoCreate : function(){
2242 html : this.html || ''
2247 cls : 'modal-title',
2251 if(this.specificTitle){
2257 if (this.allow_close) {
2268 style : 'display: none',
2271 cls: "modal-dialog",
2274 cls : "modal-content",
2277 cls : 'modal-header',
2282 cls : 'modal-footer',
2286 cls: 'btn-' + this.buttonPosition
2303 modal.cls += ' fade';
2309 getChildContainer : function() {
2314 getButtonContainer : function() {
2315 return this.el.select('.modal-footer div',true).first();
2318 initEvents : function()
2320 if (this.allow_close) {
2321 this.closeEl.on('click', this.hide, this);
2327 if (!this.rendered) {
2331 this.el.setStyle('display', 'block');
2335 (function(){ _this.el.addClass('in'); }).defer(50);
2337 this.el.addClass('in');
2340 // not sure how we can show data in here..
2342 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2345 Roo.get(document.body).addClass("x-body-masked");
2346 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2348 this.el.setStyle('zIndex', '10001');
2350 this.fireEvent('show', this);
2357 Roo.get(document.body).removeClass("x-body-masked");
2358 this.el.removeClass('in');
2362 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2364 this.el.setStyle('display', 'none');
2367 this.fireEvent('hide', this);
2370 addButton : function(str, cb)
2374 var b = Roo.apply({}, { html : str } );
2375 b.xns = b.xns || Roo.bootstrap;
2376 b.xtype = b.xtype || 'Button';
2377 if (typeof(b.listeners) == 'undefined') {
2378 b.listeners = { click : cb.createDelegate(this) };
2381 var btn = Roo.factory(b);
2383 btn.onRender(this.el.select('.modal-footer div').first());
2389 setDefaultButton : function(btn)
2391 //this.el.select('.modal-footer').()
2393 resizeTo: function(w,h)
2397 setContentSize : function(w, h)
2401 onButtonClick: function(btn,e)
2404 this.fireEvent('btnclick', btn.name, e);
2407 * Set the title of the Dialog
2408 * @param {String} str new Title
2410 setTitle: function(str) {
2411 this.titleEl.dom.innerHTML = str;
2414 * Set the body of the Dialog
2415 * @param {String} str new Title
2417 setBody: function(str) {
2418 this.bodyEl.dom.innerHTML = str;
2421 * Set the body of the Dialog using the template
2422 * @param {Obj} data - apply this data to the template and replace the body contents.
2424 applyBody: function(obj)
2427 Roo.log("Error - using apply Body without a template");
2430 this.tmpl.overwrite(this.bodyEl, obj);
2436 Roo.apply(Roo.bootstrap.Modal, {
2438 * Button config that displays a single OK button
2447 * Button config that displays Yes and No buttons
2463 * Button config that displays OK and Cancel buttons
2478 * Button config that displays Yes, No and Cancel buttons
2501 * messagebox - can be used as a replace
2505 * @class Roo.MessageBox
2506 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2510 Roo.Msg.alert('Status', 'Changes saved successfully.');
2512 // Prompt for user data:
2513 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2515 // process text value...
2519 // Show a dialog using config options:
2521 title:'Save Changes?',
2522 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2523 buttons: Roo.Msg.YESNOCANCEL,
2530 Roo.bootstrap.MessageBox = function(){
2531 var dlg, opt, mask, waitTimer;
2532 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2533 var buttons, activeTextEl, bwidth;
2537 var handleButton = function(button){
2539 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2543 var handleHide = function(){
2545 dlg.el.removeClass(opt.cls);
2548 // Roo.TaskMgr.stop(waitTimer);
2549 // waitTimer = null;
2554 var updateButtons = function(b){
2557 buttons["ok"].hide();
2558 buttons["cancel"].hide();
2559 buttons["yes"].hide();
2560 buttons["no"].hide();
2561 //dlg.footer.dom.style.display = 'none';
2564 dlg.footerEl.dom.style.display = '';
2565 for(var k in buttons){
2566 if(typeof buttons[k] != "function"){
2569 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2570 width += buttons[k].el.getWidth()+15;
2580 var handleEsc = function(d, k, e){
2581 if(opt && opt.closable !== false){
2591 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2592 * @return {Roo.BasicDialog} The BasicDialog element
2594 getDialog : function(){
2596 dlg = new Roo.bootstrap.Modal( {
2599 //constraintoviewport:false,
2601 //collapsible : false,
2606 //buttonAlign:"center",
2607 closeClick : function(){
2608 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2611 handleButton("cancel");
2616 dlg.on("hide", handleHide);
2618 //dlg.addKeyListener(27, handleEsc);
2620 this.buttons = buttons;
2621 var bt = this.buttonText;
2622 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2623 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2624 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2625 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2627 bodyEl = dlg.bodyEl.createChild({
2629 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2630 '<textarea class="roo-mb-textarea"></textarea>' +
2631 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2633 msgEl = bodyEl.dom.firstChild;
2634 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2635 textboxEl.enableDisplayMode();
2636 textboxEl.addKeyListener([10,13], function(){
2637 if(dlg.isVisible() && opt && opt.buttons){
2640 }else if(opt.buttons.yes){
2641 handleButton("yes");
2645 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2646 textareaEl.enableDisplayMode();
2647 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2648 progressEl.enableDisplayMode();
2649 var pf = progressEl.dom.firstChild;
2651 pp = Roo.get(pf.firstChild);
2652 pp.setHeight(pf.offsetHeight);
2660 * Updates the message box body text
2661 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2662 * the XHTML-compliant non-breaking space character '&#160;')
2663 * @return {Roo.MessageBox} This message box
2665 updateText : function(text){
2666 if(!dlg.isVisible() && !opt.width){
2667 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2669 msgEl.innerHTML = text || ' ';
2671 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2672 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2674 Math.min(opt.width || cw , this.maxWidth),
2675 Math.max(opt.minWidth || this.minWidth, bwidth)
2678 activeTextEl.setWidth(w);
2680 if(dlg.isVisible()){
2681 dlg.fixedcenter = false;
2683 // to big, make it scroll. = But as usual stupid IE does not support
2686 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2687 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2688 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2690 bodyEl.dom.style.height = '';
2691 bodyEl.dom.style.overflowY = '';
2694 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2696 bodyEl.dom.style.overflowX = '';
2699 dlg.setContentSize(w, bodyEl.getHeight());
2700 if(dlg.isVisible()){
2701 dlg.fixedcenter = true;
2707 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2708 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2709 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2710 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2711 * @return {Roo.MessageBox} This message box
2713 updateProgress : function(value, text){
2715 this.updateText(text);
2717 if (pp) { // weird bug on my firefox - for some reason this is not defined
2718 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2724 * Returns true if the message box is currently displayed
2725 * @return {Boolean} True if the message box is visible, else false
2727 isVisible : function(){
2728 return dlg && dlg.isVisible();
2732 * Hides the message box if it is displayed
2735 if(this.isVisible()){
2741 * Displays a new message box, or reinitializes an existing message box, based on the config options
2742 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2743 * The following config object properties are supported:
2745 Property Type Description
2746 ---------- --------------- ------------------------------------------------------------------------------------
2747 animEl String/Element An id or Element from which the message box should animate as it opens and
2748 closes (defaults to undefined)
2749 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2750 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2751 closable Boolean False to hide the top-right close button (defaults to true). Note that
2752 progress and wait dialogs will ignore this property and always hide the
2753 close button as they can only be closed programmatically.
2754 cls String A custom CSS class to apply to the message box element
2755 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2756 displayed (defaults to 75)
2757 fn Function A callback function to execute after closing the dialog. The arguments to the
2758 function will be btn (the name of the button that was clicked, if applicable,
2759 e.g. "ok"), and text (the value of the active text field, if applicable).
2760 Progress and wait dialogs will ignore this option since they do not respond to
2761 user actions and can only be closed programmatically, so any required function
2762 should be called by the same code after it closes the dialog.
2763 icon String A CSS class that provides a background image to be used as an icon for
2764 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2765 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2766 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2767 modal Boolean False to allow user interaction with the page while the message box is
2768 displayed (defaults to true)
2769 msg String A string that will replace the existing message box body text (defaults
2770 to the XHTML-compliant non-breaking space character ' ')
2771 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2772 progress Boolean True to display a progress bar (defaults to false)
2773 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2774 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2775 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2776 title String The title text
2777 value String The string value to set into the active textbox element if displayed
2778 wait Boolean True to display a progress bar (defaults to false)
2779 width Number The width of the dialog in pixels
2786 msg: 'Please enter your address:',
2788 buttons: Roo.MessageBox.OKCANCEL,
2791 animEl: 'addAddressBtn'
2794 * @param {Object} config Configuration options
2795 * @return {Roo.MessageBox} This message box
2797 show : function(options)
2800 // this causes nightmares if you show one dialog after another
2801 // especially on callbacks..
2803 if(this.isVisible()){
2806 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2807 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2808 Roo.log("New Dialog Message:" + options.msg )
2809 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2810 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2813 var d = this.getDialog();
2815 d.setTitle(opt.title || " ");
2816 d.closeEl.setDisplayed(opt.closable !== false);
2817 activeTextEl = textboxEl;
2818 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2823 textareaEl.setHeight(typeof opt.multiline == "number" ?
2824 opt.multiline : this.defaultTextHeight);
2825 activeTextEl = textareaEl;
2834 progressEl.setDisplayed(opt.progress === true);
2835 this.updateProgress(0);
2836 activeTextEl.dom.value = opt.value || "";
2838 dlg.setDefaultButton(activeTextEl);
2840 var bs = opt.buttons;
2844 }else if(bs && bs.yes){
2845 db = buttons["yes"];
2847 dlg.setDefaultButton(db);
2849 bwidth = updateButtons(opt.buttons);
2850 this.updateText(opt.msg);
2852 d.el.addClass(opt.cls);
2854 d.proxyDrag = opt.proxyDrag === true;
2855 d.modal = opt.modal !== false;
2856 d.mask = opt.modal !== false ? mask : false;
2858 // force it to the end of the z-index stack so it gets a cursor in FF
2859 document.body.appendChild(dlg.el.dom);
2860 d.animateTarget = null;
2861 d.show(options.animEl);
2867 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2868 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2869 * and closing the message box when the process is complete.
2870 * @param {String} title The title bar text
2871 * @param {String} msg The message box body text
2872 * @return {Roo.MessageBox} This message box
2874 progress : function(title, msg){
2881 minWidth: this.minProgressWidth,
2888 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2889 * If a callback function is passed it will be called after the user clicks the button, and the
2890 * id of the button that was clicked will be passed as the only parameter to the callback
2891 * (could also be the top-right close button).
2892 * @param {String} title The title bar text
2893 * @param {String} msg The message box body text
2894 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2895 * @param {Object} scope (optional) The scope of the callback function
2896 * @return {Roo.MessageBox} This message box
2898 alert : function(title, msg, fn, scope){
2911 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2912 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2913 * You are responsible for closing the message box when the process is complete.
2914 * @param {String} msg The message box body text
2915 * @param {String} title (optional) The title bar text
2916 * @return {Roo.MessageBox} This message box
2918 wait : function(msg, title){
2929 waitTimer = Roo.TaskMgr.start({
2931 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2939 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2940 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2941 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2942 * @param {String} title The title bar text
2943 * @param {String} msg The message box body text
2944 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2945 * @param {Object} scope (optional) The scope of the callback function
2946 * @return {Roo.MessageBox} This message box
2948 confirm : function(title, msg, fn, scope){
2952 buttons: this.YESNO,
2961 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2962 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2963 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2964 * (could also be the top-right close button) and the text that was entered will be passed as the two
2965 * parameters to the callback.
2966 * @param {String} title The title bar text
2967 * @param {String} msg The message box body text
2968 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2969 * @param {Object} scope (optional) The scope of the callback function
2970 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2971 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2972 * @return {Roo.MessageBox} This message box
2974 prompt : function(title, msg, fn, scope, multiline){
2978 buttons: this.OKCANCEL,
2983 multiline: multiline,
2990 * Button config that displays a single OK button
2995 * Button config that displays Yes and No buttons
2998 YESNO : {yes:true, no:true},
3000 * Button config that displays OK and Cancel buttons
3003 OKCANCEL : {ok:true, cancel:true},
3005 * Button config that displays Yes, No and Cancel buttons
3008 YESNOCANCEL : {yes:true, no:true, cancel:true},
3011 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3014 defaultTextHeight : 75,
3016 * The maximum width in pixels of the message box (defaults to 600)
3021 * The minimum width in pixels of the message box (defaults to 100)
3026 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3027 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3030 minProgressWidth : 250,
3032 * An object containing the default button text strings that can be overriden for localized language support.
3033 * Supported properties are: ok, cancel, yes and no.
3034 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3047 * Shorthand for {@link Roo.MessageBox}
3049 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3050 Roo.Msg = Roo.Msg || Roo.MessageBox;
3059 * @class Roo.bootstrap.Navbar
3060 * @extends Roo.bootstrap.Component
3061 * Bootstrap Navbar class
3064 * Create a new Navbar
3065 * @param {Object} config The config object
3069 Roo.bootstrap.Navbar = function(config){
3070 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3074 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3083 getAutoCreate : function(){
3086 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3090 initEvents :function ()
3092 //Roo.log(this.el.select('.navbar-toggle',true));
3093 this.el.select('.navbar-toggle',true).on('click', function() {
3094 // Roo.log('click');
3095 this.el.select('.navbar-collapse',true).toggleClass('in');
3103 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3105 var size = this.el.getSize();
3106 this.maskEl.setSize(size.width, size.height);
3107 this.maskEl.enableDisplayMode("block");
3116 getChildContainer : function()
3118 if (this.el.select('.collapse').getCount()) {
3119 return this.el.select('.collapse',true).first();
3152 * @class Roo.bootstrap.NavSimplebar
3153 * @extends Roo.bootstrap.Navbar
3154 * Bootstrap Sidebar class
3156 * @cfg {Boolean} inverse is inverted color
3158 * @cfg {String} type (nav | pills | tabs)
3159 * @cfg {Boolean} arrangement stacked | justified
3160 * @cfg {String} align (left | right) alignment
3162 * @cfg {Boolean} main (true|false) main nav bar? default false
3163 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3165 * @cfg {String} tag (header|footer|nav|div) default is nav
3171 * Create a new Sidebar
3172 * @param {Object} config The config object
3176 Roo.bootstrap.NavSimplebar = function(config){
3177 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3180 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3196 getAutoCreate : function(){
3200 tag : this.tag || 'div',
3213 this.type = this.type || 'nav';
3214 if (['tabs','pills'].indexOf(this.type)!==-1) {
3215 cfg.cn[0].cls += ' nav-' + this.type
3219 if (this.type!=='nav') {
3220 Roo.log('nav type must be nav/tabs/pills')
3222 cfg.cn[0].cls += ' navbar-nav'
3228 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3229 cfg.cn[0].cls += ' nav-' + this.arrangement;
3233 if (this.align === 'right') {
3234 cfg.cn[0].cls += ' navbar-right';
3238 cfg.cls += ' navbar-inverse';
3265 * @class Roo.bootstrap.NavHeaderbar
3266 * @extends Roo.bootstrap.NavSimplebar
3267 * Bootstrap Sidebar class
3269 * @cfg {String} brand what is brand
3270 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3271 * @cfg {String} brand_href href of the brand
3272 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3273 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3274 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3275 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3278 * Create a new Sidebar
3279 * @param {Object} config The config object
3283 Roo.bootstrap.NavHeaderbar = function(config){
3284 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3288 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3295 desktopCenter : false,
3298 getAutoCreate : function(){
3301 tag: this.nav || 'nav',
3308 if (this.desktopCenter) {
3309 cn.push({cls : 'container', cn : []});
3316 cls: 'navbar-header',
3321 cls: 'navbar-toggle',
3322 'data-toggle': 'collapse',
3327 html: 'Toggle navigation'
3349 cls: 'collapse navbar-collapse',
3353 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3355 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3356 cfg.cls += ' navbar-' + this.position;
3358 // tag can override this..
3360 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3363 if (this.brand !== '') {
3366 href: this.brand_href ? this.brand_href : '#',
3367 cls: 'navbar-brand',
3375 cfg.cls += ' main-nav';
3383 getHeaderChildContainer : function()
3385 if (this.el.select('.navbar-header').getCount()) {
3386 return this.el.select('.navbar-header',true).first();
3389 return this.getChildContainer();
3393 initEvents : function()
3395 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3397 if (this.autohide) {
3402 Roo.get(document).on('scroll',function(e) {
3403 var ns = Roo.get(document).getScroll().top;
3404 var os = prevScroll;
3408 ft.removeClass('slideDown');
3409 ft.addClass('slideUp');
3412 ft.removeClass('slideUp');
3413 ft.addClass('slideDown');
3434 * @class Roo.bootstrap.NavSidebar
3435 * @extends Roo.bootstrap.Navbar
3436 * Bootstrap Sidebar class
3439 * Create a new Sidebar
3440 * @param {Object} config The config object
3444 Roo.bootstrap.NavSidebar = function(config){
3445 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3448 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3450 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3452 getAutoCreate : function(){
3457 cls: 'sidebar sidebar-nav'
3479 * @class Roo.bootstrap.NavGroup
3480 * @extends Roo.bootstrap.Component
3481 * Bootstrap NavGroup class
3482 * @cfg {String} align left | right
3483 * @cfg {Boolean} inverse false | true
3484 * @cfg {String} type (nav|pills|tab) default nav
3485 * @cfg {String} navId - reference Id for navbar.
3489 * Create a new nav group
3490 * @param {Object} config The config object
3493 Roo.bootstrap.NavGroup = function(config){
3494 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3497 Roo.bootstrap.NavGroup.register(this);
3501 * Fires when the active item changes
3502 * @param {Roo.bootstrap.NavGroup} this
3503 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3504 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3511 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3522 getAutoCreate : function()
3524 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3531 if (['tabs','pills'].indexOf(this.type)!==-1) {
3532 cfg.cls += ' nav-' + this.type
3534 if (this.type!=='nav') {
3535 Roo.log('nav type must be nav/tabs/pills')
3537 cfg.cls += ' navbar-nav'
3540 if (this.parent().sidebar) {
3543 cls: 'dashboard-menu sidebar-menu'
3549 if (this.form === true) {
3555 if (this.align === 'right') {
3556 cfg.cls += ' navbar-right';
3558 cfg.cls += ' navbar-left';
3562 if (this.align === 'right') {
3563 cfg.cls += ' navbar-right';
3567 cfg.cls += ' navbar-inverse';
3575 * sets the active Navigation item
3576 * @param {Roo.bootstrap.NavItem} the new current navitem
3578 setActiveItem : function(item)
3581 Roo.each(this.navItems, function(v){
3586 v.setActive(false, true);
3593 item.setActive(true, true);
3594 this.fireEvent('changed', this, item, prev);
3599 * gets the active Navigation item
3600 * @return {Roo.bootstrap.NavItem} the current navitem
3602 getActive : function()
3606 Roo.each(this.navItems, function(v){
3617 indexOfNav : function()
3621 Roo.each(this.navItems, function(v,i){
3632 * adds a Navigation item
3633 * @param {Roo.bootstrap.NavItem} the navitem to add
3635 addItem : function(cfg)
3637 var cn = new Roo.bootstrap.NavItem(cfg);
3639 cn.parentId = this.id;
3640 cn.onRender(this.el, null);
3644 * register a Navigation item
3645 * @param {Roo.bootstrap.NavItem} the navitem to add
3647 register : function(item)
3649 this.navItems.push( item);
3650 item.navId = this.navId;
3655 * clear all the Navigation item
3658 clearAll : function()
3661 this.el.dom.innerHTML = '';
3664 getNavItem: function(tabId)
3667 Roo.each(this.navItems, function(e) {
3668 if (e.tabId == tabId) {
3678 setActiveNext : function()
3680 var i = this.indexOfNav(this.getActive());
3681 if (i > this.navItems.length) {
3684 this.setActiveItem(this.navItems[i+1]);
3686 setActivePrev : function()
3688 var i = this.indexOfNav(this.getActive());
3692 this.setActiveItem(this.navItems[i-1]);
3694 clearWasActive : function(except) {
3695 Roo.each(this.navItems, function(e) {
3696 if (e.tabId != except.tabId && e.was_active) {
3697 e.was_active = false;
3704 getWasActive : function ()
3707 Roo.each(this.navItems, function(e) {
3722 Roo.apply(Roo.bootstrap.NavGroup, {
3726 * register a Navigation Group
3727 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3729 register : function(navgrp)
3731 this.groups[navgrp.navId] = navgrp;
3735 * fetch a Navigation Group based on the navigation ID
3736 * @param {string} the navgroup to add
3737 * @returns {Roo.bootstrap.NavGroup} the navgroup
3739 get: function(navId) {
3740 if (typeof(this.groups[navId]) == 'undefined') {
3742 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3744 return this.groups[navId] ;
3759 * @class Roo.bootstrap.NavItem
3760 * @extends Roo.bootstrap.Component
3761 * Bootstrap Navbar.NavItem class
3762 * @cfg {String} href link to
3763 * @cfg {String} html content of button
3764 * @cfg {String} badge text inside badge
3765 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3766 * @cfg {String} glyphicon name of glyphicon
3767 * @cfg {String} icon name of font awesome icon
3768 * @cfg {Boolean} active Is item active
3769 * @cfg {Boolean} disabled Is item disabled
3771 * @cfg {Boolean} preventDefault (true | false) default false
3772 * @cfg {String} tabId the tab that this item activates.
3773 * @cfg {String} tagtype (a|span) render as a href or span?
3774 * @cfg {Boolean} animateRef (true|false) link to element default false
3777 * Create a new Navbar Item
3778 * @param {Object} config The config object
3780 Roo.bootstrap.NavItem = function(config){
3781 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3786 * The raw click event for the entire grid.
3787 * @param {Roo.EventObject} e
3792 * Fires when the active item active state changes
3793 * @param {Roo.bootstrap.NavItem} this
3794 * @param {boolean} state the new state
3800 * Fires when scroll to element
3801 * @param {Roo.bootstrap.NavItem} this
3802 * @param {Object} options
3803 * @param {Roo.EventObject} e
3811 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3819 preventDefault : false,
3826 getAutoCreate : function(){
3834 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3836 if (this.disabled) {
3837 cfg.cls += ' disabled';
3840 if (this.href || this.html || this.glyphicon || this.icon) {
3844 href : this.href || "#",
3845 html: this.html || ''
3850 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3853 if(this.glyphicon) {
3854 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3859 cfg.cn[0].html += " <span class='caret'></span>";
3863 if (this.badge !== '') {
3865 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3873 initEvents: function()
3875 if (typeof (this.menu) != 'undefined') {
3876 this.menu.parentType = this.xtype;
3877 this.menu.triggerEl = this.el;
3878 this.menu = this.addxtype(Roo.apply({}, this.menu));
3881 this.el.select('a',true).on('click', this.onClick, this);
3883 if(this.tagtype == 'span'){
3884 this.el.select('span',true).on('click', this.onClick, this);
3887 // at this point parent should be available..
3888 this.parent().register(this);
3891 onClick : function(e)
3894 this.preventDefault ||
3901 if (this.disabled) {
3905 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3906 if (tg && tg.transition) {
3907 Roo.log("waiting for the transitionend");
3913 //Roo.log("fire event clicked");
3914 if(this.fireEvent('click', this, e) === false){
3918 if(this.tagtype == 'span'){
3922 //Roo.log(this.href);
3923 var ael = this.el.select('a',true).first();
3926 if(ael && this.animateRef && this.href.indexOf('#') > -1){
3927 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
3928 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
3929 return; // ignore... - it's a 'hash' to another page.
3933 this.scrollToElement(e);
3937 var p = this.parent();
3939 if (['tabs','pills'].indexOf(p.type)!==-1) {
3940 if (typeof(p.setActiveItem) !== 'undefined') {
3941 p.setActiveItem(this);
3946 isActive: function () {
3949 setActive : function(state, fire, is_was_active)
3951 if (this.active && !state & this.navId) {
3952 this.was_active = true;
3953 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3955 nv.clearWasActive(this);
3959 this.active = state;
3962 this.el.removeClass('active');
3963 } else if (!this.el.hasClass('active')) {
3964 this.el.addClass('active');
3967 this.fireEvent('changed', this, state);
3970 // show a panel if it's registered and related..
3972 if (!this.navId || !this.tabId || !state || is_was_active) {
3976 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3980 var pan = tg.getPanelByName(this.tabId);
3984 // if we can not flip to new panel - go back to old nav highlight..
3985 if (false == tg.showPanel(pan)) {
3986 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3988 var onav = nv.getWasActive();
3990 onav.setActive(true, false, true);
3999 // this should not be here...
4000 setDisabled : function(state)
4002 this.disabled = state;
4004 this.el.removeClass('disabled');
4005 } else if (!this.el.hasClass('disabled')) {
4006 this.el.addClass('disabled');
4012 * Fetch the element to display the tooltip on.
4013 * @return {Roo.Element} defaults to this.el
4015 tooltipEl : function()
4017 return this.el.select('' + this.tagtype + '', true).first();
4020 scrollToElement : function(e)
4022 var c = document.body;
4025 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4027 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4028 c = document.documentElement;
4031 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4037 var o = target.calcOffsetsTo(c);
4044 this.fireEvent('scrollto', this, options, e);
4046 Roo.get(c).scrollTo('top', options.value, true);
4059 * <span> icon </span>
4060 * <span> text </span>
4061 * <span>badge </span>
4065 * @class Roo.bootstrap.NavSidebarItem
4066 * @extends Roo.bootstrap.NavItem
4067 * Bootstrap Navbar.NavSidebarItem class
4069 * Create a new Navbar Button
4070 * @param {Object} config The config object
4072 Roo.bootstrap.NavSidebarItem = function(config){
4073 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4078 * The raw click event for the entire grid.
4079 * @param {Roo.EventObject} e
4084 * Fires when the active item active state changes
4085 * @param {Roo.bootstrap.NavSidebarItem} this
4086 * @param {boolean} state the new state
4094 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4097 getAutoCreate : function(){
4102 href : this.href || '#',
4114 html : this.html || ''
4119 cfg.cls += ' active';
4123 if (this.glyphicon || this.icon) {
4124 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4125 a.cn.push({ tag : 'i', cls : c }) ;
4130 if (this.badge !== '') {
4131 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4135 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4136 a.cls += 'dropdown-toggle treeview' ;
4160 * @class Roo.bootstrap.Row
4161 * @extends Roo.bootstrap.Component
4162 * Bootstrap Row class (contains columns...)
4166 * @param {Object} config The config object
4169 Roo.bootstrap.Row = function(config){
4170 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4173 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4175 getAutoCreate : function(){
4194 * @class Roo.bootstrap.Element
4195 * @extends Roo.bootstrap.Component
4196 * Bootstrap Element class
4197 * @cfg {String} html contents of the element
4198 * @cfg {String} tag tag of the element
4199 * @cfg {String} cls class of the element
4200 * @cfg {Boolean} preventDefault (true|false) default false
4201 * @cfg {Boolean} clickable (true|false) default false
4204 * Create a new Element
4205 * @param {Object} config The config object
4208 Roo.bootstrap.Element = function(config){
4209 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4215 * When a element is chick
4216 * @param {Roo.bootstrap.Element} this
4217 * @param {Roo.EventObject} e
4223 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4228 preventDefault: false,
4231 getAutoCreate : function(){
4242 initEvents: function()
4244 Roo.bootstrap.Element.superclass.initEvents.call(this);
4247 this.el.on('click', this.onClick, this);
4252 onClick : function(e)
4254 if(this.preventDefault){
4258 this.fireEvent('click', this, e);
4261 getValue : function()
4263 return this.el.dom.innerHTML;
4266 setValue : function(value)
4268 this.el.dom.innerHTML = value;
4283 * @class Roo.bootstrap.Pagination
4284 * @extends Roo.bootstrap.Component
4285 * Bootstrap Pagination class
4286 * @cfg {String} size xs | sm | md | lg
4287 * @cfg {Boolean} inverse false | true
4290 * Create a new Pagination
4291 * @param {Object} config The config object
4294 Roo.bootstrap.Pagination = function(config){
4295 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4298 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4304 getAutoCreate : function(){
4310 cfg.cls += ' inverse';
4316 cfg.cls += " " + this.cls;
4334 * @class Roo.bootstrap.PaginationItem
4335 * @extends Roo.bootstrap.Component
4336 * Bootstrap PaginationItem class
4337 * @cfg {String} html text
4338 * @cfg {String} href the link
4339 * @cfg {Boolean} preventDefault (true | false) default true
4340 * @cfg {Boolean} active (true | false) default false
4341 * @cfg {Boolean} disabled default false
4345 * Create a new PaginationItem
4346 * @param {Object} config The config object
4350 Roo.bootstrap.PaginationItem = function(config){
4351 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4356 * The raw click event for the entire grid.
4357 * @param {Roo.EventObject} e
4363 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4367 preventDefault: true,
4372 getAutoCreate : function(){
4378 href : this.href ? this.href : '#',
4379 html : this.html ? this.html : ''
4389 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4393 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4399 initEvents: function() {
4401 this.el.on('click', this.onClick, this);
4404 onClick : function(e)
4406 Roo.log('PaginationItem on click ');
4407 if(this.preventDefault){
4415 this.fireEvent('click', this, e);
4431 * @class Roo.bootstrap.Slider
4432 * @extends Roo.bootstrap.Component
4433 * Bootstrap Slider class
4436 * Create a new Slider
4437 * @param {Object} config The config object
4440 Roo.bootstrap.Slider = function(config){
4441 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4444 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4446 getAutoCreate : function(){
4450 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4454 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4466 * Ext JS Library 1.1.1
4467 * Copyright(c) 2006-2007, Ext JS, LLC.
4469 * Originally Released Under LGPL - original licence link has changed is not relivant.
4472 * <script type="text/javascript">
4477 * @class Roo.grid.ColumnModel
4478 * @extends Roo.util.Observable
4479 * This is the default implementation of a ColumnModel used by the Grid. It defines
4480 * the columns in the grid.
4483 var colModel = new Roo.grid.ColumnModel([
4484 {header: "Ticker", width: 60, sortable: true, locked: true},
4485 {header: "Company Name", width: 150, sortable: true},
4486 {header: "Market Cap.", width: 100, sortable: true},
4487 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4488 {header: "Employees", width: 100, sortable: true, resizable: false}
4493 * The config options listed for this class are options which may appear in each
4494 * individual column definition.
4495 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4497 * @param {Object} config An Array of column config objects. See this class's
4498 * config objects for details.
4500 Roo.grid.ColumnModel = function(config){
4502 * The config passed into the constructor
4504 this.config = config;
4507 // if no id, create one
4508 // if the column does not have a dataIndex mapping,
4509 // map it to the order it is in the config
4510 for(var i = 0, len = config.length; i < len; i++){
4512 if(typeof c.dataIndex == "undefined"){
4515 if(typeof c.renderer == "string"){
4516 c.renderer = Roo.util.Format[c.renderer];
4518 if(typeof c.id == "undefined"){
4521 if(c.editor && c.editor.xtype){
4522 c.editor = Roo.factory(c.editor, Roo.grid);
4524 if(c.editor && c.editor.isFormField){
4525 c.editor = new Roo.grid.GridEditor(c.editor);
4527 this.lookup[c.id] = c;
4531 * The width of columns which have no width specified (defaults to 100)
4534 this.defaultWidth = 100;
4537 * Default sortable of columns which have no sortable specified (defaults to false)
4540 this.defaultSortable = false;
4544 * @event widthchange
4545 * Fires when the width of a column changes.
4546 * @param {ColumnModel} this
4547 * @param {Number} columnIndex The column index
4548 * @param {Number} newWidth The new width
4550 "widthchange": true,
4552 * @event headerchange
4553 * Fires when the text of a header changes.
4554 * @param {ColumnModel} this
4555 * @param {Number} columnIndex The column index
4556 * @param {Number} newText The new header text
4558 "headerchange": true,
4560 * @event hiddenchange
4561 * Fires when a column is hidden or "unhidden".
4562 * @param {ColumnModel} this
4563 * @param {Number} columnIndex The column index
4564 * @param {Boolean} hidden true if hidden, false otherwise
4566 "hiddenchange": true,
4568 * @event columnmoved
4569 * Fires when a column is moved.
4570 * @param {ColumnModel} this
4571 * @param {Number} oldIndex
4572 * @param {Number} newIndex
4574 "columnmoved" : true,
4576 * @event columlockchange
4577 * Fires when a column's locked state is changed
4578 * @param {ColumnModel} this
4579 * @param {Number} colIndex
4580 * @param {Boolean} locked true if locked
4582 "columnlockchange" : true
4584 Roo.grid.ColumnModel.superclass.constructor.call(this);
4586 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4588 * @cfg {String} header The header text to display in the Grid view.
4591 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4592 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4593 * specified, the column's index is used as an index into the Record's data Array.
4596 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4597 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4600 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4601 * Defaults to the value of the {@link #defaultSortable} property.
4602 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4605 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4608 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4611 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4614 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4617 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4618 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4619 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4620 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4623 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4626 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4629 * @cfg {String} cursor (Optional)
4632 * @cfg {String} tooltip (Optional)
4635 * Returns the id of the column at the specified index.
4636 * @param {Number} index The column index
4637 * @return {String} the id
4639 getColumnId : function(index){
4640 return this.config[index].id;
4644 * Returns the column for a specified id.
4645 * @param {String} id The column id
4646 * @return {Object} the column
4648 getColumnById : function(id){
4649 return this.lookup[id];
4654 * Returns the column for a specified dataIndex.
4655 * @param {String} dataIndex The column dataIndex
4656 * @return {Object|Boolean} the column or false if not found
4658 getColumnByDataIndex: function(dataIndex){
4659 var index = this.findColumnIndex(dataIndex);
4660 return index > -1 ? this.config[index] : false;
4664 * Returns the index for a specified column id.
4665 * @param {String} id The column id
4666 * @return {Number} the index, or -1 if not found
4668 getIndexById : function(id){
4669 for(var i = 0, len = this.config.length; i < len; i++){
4670 if(this.config[i].id == id){
4678 * Returns the index for a specified column dataIndex.
4679 * @param {String} dataIndex The column dataIndex
4680 * @return {Number} the index, or -1 if not found
4683 findColumnIndex : function(dataIndex){
4684 for(var i = 0, len = this.config.length; i < len; i++){
4685 if(this.config[i].dataIndex == dataIndex){
4693 moveColumn : function(oldIndex, newIndex){
4694 var c = this.config[oldIndex];
4695 this.config.splice(oldIndex, 1);
4696 this.config.splice(newIndex, 0, c);
4697 this.dataMap = null;
4698 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4701 isLocked : function(colIndex){
4702 return this.config[colIndex].locked === true;
4705 setLocked : function(colIndex, value, suppressEvent){
4706 if(this.isLocked(colIndex) == value){
4709 this.config[colIndex].locked = value;
4711 this.fireEvent("columnlockchange", this, colIndex, value);
4715 getTotalLockedWidth : function(){
4717 for(var i = 0; i < this.config.length; i++){
4718 if(this.isLocked(i) && !this.isHidden(i)){
4719 this.totalWidth += this.getColumnWidth(i);
4725 getLockedCount : function(){
4726 for(var i = 0, len = this.config.length; i < len; i++){
4727 if(!this.isLocked(i)){
4734 * Returns the number of columns.
4737 getColumnCount : function(visibleOnly){
4738 if(visibleOnly === true){
4740 for(var i = 0, len = this.config.length; i < len; i++){
4741 if(!this.isHidden(i)){
4747 return this.config.length;
4751 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4752 * @param {Function} fn
4753 * @param {Object} scope (optional)
4754 * @return {Array} result
4756 getColumnsBy : function(fn, scope){
4758 for(var i = 0, len = this.config.length; i < len; i++){
4759 var c = this.config[i];
4760 if(fn.call(scope||this, c, i) === true){
4768 * Returns true if the specified column is sortable.
4769 * @param {Number} col The column index
4772 isSortable : function(col){
4773 if(typeof this.config[col].sortable == "undefined"){
4774 return this.defaultSortable;
4776 return this.config[col].sortable;
4780 * Returns the rendering (formatting) function defined for the column.
4781 * @param {Number} col The column index.
4782 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4784 getRenderer : function(col){
4785 if(!this.config[col].renderer){
4786 return Roo.grid.ColumnModel.defaultRenderer;
4788 return this.config[col].renderer;
4792 * Sets the rendering (formatting) function for a column.
4793 * @param {Number} col The column index
4794 * @param {Function} fn The function to use to process the cell's raw data
4795 * to return HTML markup for the grid view. The render function is called with
4796 * the following parameters:<ul>
4797 * <li>Data value.</li>
4798 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4799 * <li>css A CSS style string to apply to the table cell.</li>
4800 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4801 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4802 * <li>Row index</li>
4803 * <li>Column index</li>
4804 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4806 setRenderer : function(col, fn){
4807 this.config[col].renderer = fn;
4811 * Returns the width for the specified column.
4812 * @param {Number} col The column index
4815 getColumnWidth : function(col){
4816 return this.config[col].width * 1 || this.defaultWidth;
4820 * Sets the width for a column.
4821 * @param {Number} col The column index
4822 * @param {Number} width The new width
4824 setColumnWidth : function(col, width, suppressEvent){
4825 this.config[col].width = width;
4826 this.totalWidth = null;
4828 this.fireEvent("widthchange", this, col, width);
4833 * Returns the total width of all columns.
4834 * @param {Boolean} includeHidden True to include hidden column widths
4837 getTotalWidth : function(includeHidden){
4838 if(!this.totalWidth){
4839 this.totalWidth = 0;
4840 for(var i = 0, len = this.config.length; i < len; i++){
4841 if(includeHidden || !this.isHidden(i)){
4842 this.totalWidth += this.getColumnWidth(i);
4846 return this.totalWidth;
4850 * Returns the header for the specified column.
4851 * @param {Number} col The column index
4854 getColumnHeader : function(col){
4855 return this.config[col].header;
4859 * Sets the header for a column.
4860 * @param {Number} col The column index
4861 * @param {String} header The new header
4863 setColumnHeader : function(col, header){
4864 this.config[col].header = header;
4865 this.fireEvent("headerchange", this, col, header);
4869 * Returns the tooltip for the specified column.
4870 * @param {Number} col The column index
4873 getColumnTooltip : function(col){
4874 return this.config[col].tooltip;
4877 * Sets the tooltip for a column.
4878 * @param {Number} col The column index
4879 * @param {String} tooltip The new tooltip
4881 setColumnTooltip : function(col, tooltip){
4882 this.config[col].tooltip = tooltip;
4886 * Returns the dataIndex for the specified column.
4887 * @param {Number} col The column index
4890 getDataIndex : function(col){
4891 return this.config[col].dataIndex;
4895 * Sets the dataIndex for a column.
4896 * @param {Number} col The column index
4897 * @param {Number} dataIndex The new dataIndex
4899 setDataIndex : function(col, dataIndex){
4900 this.config[col].dataIndex = dataIndex;
4906 * Returns true if the cell is editable.
4907 * @param {Number} colIndex The column index
4908 * @param {Number} rowIndex The row index
4911 isCellEditable : function(colIndex, rowIndex){
4912 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4916 * Returns the editor defined for the cell/column.
4917 * return false or null to disable editing.
4918 * @param {Number} colIndex The column index
4919 * @param {Number} rowIndex The row index
4922 getCellEditor : function(colIndex, rowIndex){
4923 return this.config[colIndex].editor;
4927 * Sets if a column is editable.
4928 * @param {Number} col The column index
4929 * @param {Boolean} editable True if the column is editable
4931 setEditable : function(col, editable){
4932 this.config[col].editable = editable;
4937 * Returns true if the column is hidden.
4938 * @param {Number} colIndex The column index
4941 isHidden : function(colIndex){
4942 return this.config[colIndex].hidden;
4947 * Returns true if the column width cannot be changed
4949 isFixed : function(colIndex){
4950 return this.config[colIndex].fixed;
4954 * Returns true if the column can be resized
4957 isResizable : function(colIndex){
4958 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4961 * Sets if a column is hidden.
4962 * @param {Number} colIndex The column index
4963 * @param {Boolean} hidden True if the column is hidden
4965 setHidden : function(colIndex, hidden){
4966 this.config[colIndex].hidden = hidden;
4967 this.totalWidth = null;
4968 this.fireEvent("hiddenchange", this, colIndex, hidden);
4972 * Sets the editor for a column.
4973 * @param {Number} col The column index
4974 * @param {Object} editor The editor object
4976 setEditor : function(col, editor){
4977 this.config[col].editor = editor;
4981 Roo.grid.ColumnModel.defaultRenderer = function(value){
4982 if(typeof value == "string" && value.length < 1){
4988 // Alias for backwards compatibility
4989 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4992 * Ext JS Library 1.1.1
4993 * Copyright(c) 2006-2007, Ext JS, LLC.
4995 * Originally Released Under LGPL - original licence link has changed is not relivant.
4998 * <script type="text/javascript">
5002 * @class Roo.LoadMask
5003 * A simple utility class for generically masking elements while loading data. If the element being masked has
5004 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5005 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5006 * element's UpdateManager load indicator and will be destroyed after the initial load.
5008 * Create a new LoadMask
5009 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5010 * @param {Object} config The config object
5012 Roo.LoadMask = function(el, config){
5013 this.el = Roo.get(el);
5014 Roo.apply(this, config);
5016 this.store.on('beforeload', this.onBeforeLoad, this);
5017 this.store.on('load', this.onLoad, this);
5018 this.store.on('loadexception', this.onLoadException, this);
5019 this.removeMask = false;
5021 var um = this.el.getUpdateManager();
5022 um.showLoadIndicator = false; // disable the default indicator
5023 um.on('beforeupdate', this.onBeforeLoad, this);
5024 um.on('update', this.onLoad, this);
5025 um.on('failure', this.onLoad, this);
5026 this.removeMask = true;
5030 Roo.LoadMask.prototype = {
5032 * @cfg {Boolean} removeMask
5033 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5034 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5038 * The text to display in a centered loading message box (defaults to 'Loading...')
5042 * @cfg {String} msgCls
5043 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5045 msgCls : 'x-mask-loading',
5048 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5054 * Disables the mask to prevent it from being displayed
5056 disable : function(){
5057 this.disabled = true;
5061 * Enables the mask so that it can be displayed
5063 enable : function(){
5064 this.disabled = false;
5067 onLoadException : function()
5071 if (typeof(arguments[3]) != 'undefined') {
5072 Roo.MessageBox.alert("Error loading",arguments[3]);
5076 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5077 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5086 this.el.unmask(this.removeMask);
5091 this.el.unmask(this.removeMask);
5095 onBeforeLoad : function(){
5097 this.el.mask(this.msg, this.msgCls);
5102 destroy : function(){
5104 this.store.un('beforeload', this.onBeforeLoad, this);
5105 this.store.un('load', this.onLoad, this);
5106 this.store.un('loadexception', this.onLoadException, this);
5108 var um = this.el.getUpdateManager();
5109 um.un('beforeupdate', this.onBeforeLoad, this);
5110 um.un('update', this.onLoad, this);
5111 um.un('failure', this.onLoad, this);
5122 * @class Roo.bootstrap.Table
5123 * @extends Roo.bootstrap.Component
5124 * Bootstrap Table class
5125 * @cfg {String} cls table class
5126 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5127 * @cfg {String} bgcolor Specifies the background color for a table
5128 * @cfg {Number} border Specifies whether the table cells should have borders or not
5129 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5130 * @cfg {Number} cellspacing Specifies the space between cells
5131 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5132 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5133 * @cfg {String} sortable Specifies that the table should be sortable
5134 * @cfg {String} summary Specifies a summary of the content of a table
5135 * @cfg {Number} width Specifies the width of a table
5136 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5138 * @cfg {boolean} striped Should the rows be alternative striped
5139 * @cfg {boolean} bordered Add borders to the table
5140 * @cfg {boolean} hover Add hover highlighting
5141 * @cfg {boolean} condensed Format condensed
5142 * @cfg {boolean} responsive Format condensed
5143 * @cfg {Boolean} loadMask (true|false) default false
5144 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5145 * @cfg {Boolean} thead (true|false) generate thead, default true
5146 * @cfg {Boolean} RowSelection (true|false) default false
5147 * @cfg {Boolean} CellSelection (true|false) default false
5148 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5152 * Create a new Table
5153 * @param {Object} config The config object
5156 Roo.bootstrap.Table = function(config){
5157 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5160 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5161 this.sm = this.selModel;
5162 this.sm.xmodule = this.xmodule || false;
5164 if (this.cm && typeof(this.cm.config) == 'undefined') {
5165 this.colModel = new Roo.grid.ColumnModel(this.cm);
5166 this.cm = this.colModel;
5167 this.cm.xmodule = this.xmodule || false;
5170 this.store= Roo.factory(this.store, Roo.data);
5171 this.ds = this.store;
5172 this.ds.xmodule = this.xmodule || false;
5175 if (this.footer && this.store) {
5176 this.footer.dataSource = this.ds;
5177 this.footer = Roo.factory(this.footer);
5184 * Fires when a cell is clicked
5185 * @param {Roo.bootstrap.Table} this
5186 * @param {Roo.Element} el
5187 * @param {Number} rowIndex
5188 * @param {Number} columnIndex
5189 * @param {Roo.EventObject} e
5193 * @event celldblclick
5194 * Fires when a cell is double clicked
5195 * @param {Roo.bootstrap.Table} this
5196 * @param {Roo.Element} el
5197 * @param {Number} rowIndex
5198 * @param {Number} columnIndex
5199 * @param {Roo.EventObject} e
5201 "celldblclick" : true,
5204 * Fires when a row is clicked
5205 * @param {Roo.bootstrap.Table} this
5206 * @param {Roo.Element} el
5207 * @param {Number} rowIndex
5208 * @param {Roo.EventObject} e
5212 * @event rowdblclick
5213 * Fires when a row is double clicked
5214 * @param {Roo.bootstrap.Table} this
5215 * @param {Roo.Element} el
5216 * @param {Number} rowIndex
5217 * @param {Roo.EventObject} e
5219 "rowdblclick" : true,
5222 * Fires when a mouseover occur
5223 * @param {Roo.bootstrap.Table} this
5224 * @param {Roo.Element} el
5225 * @param {Number} rowIndex
5226 * @param {Number} columnIndex
5227 * @param {Roo.EventObject} e
5232 * Fires when a mouseout occur
5233 * @param {Roo.bootstrap.Table} this
5234 * @param {Roo.Element} el
5235 * @param {Number} rowIndex
5236 * @param {Number} columnIndex
5237 * @param {Roo.EventObject} e
5242 * Fires when a row is rendered, so you can change add a style to it.
5243 * @param {Roo.bootstrap.Table} this
5244 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5248 * @event rowsrendered
5249 * Fires when all the rows have been rendered
5250 * @param {Roo.bootstrap.Table} this
5252 'rowsrendered' : true
5257 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5281 RowSelection : false,
5282 CellSelection : false,
5285 // Roo.Element - the tbody
5288 getAutoCreate : function(){
5289 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5298 cfg.cls += ' table-striped';
5302 cfg.cls += ' table-hover';
5304 if (this.bordered) {
5305 cfg.cls += ' table-bordered';
5307 if (this.condensed) {
5308 cfg.cls += ' table-condensed';
5310 if (this.responsive) {
5311 cfg.cls += ' table-responsive';
5315 cfg.cls+= ' ' +this.cls;
5318 // this lot should be simplifed...
5321 cfg.align=this.align;
5324 cfg.bgcolor=this.bgcolor;
5327 cfg.border=this.border;
5329 if (this.cellpadding) {
5330 cfg.cellpadding=this.cellpadding;
5332 if (this.cellspacing) {
5333 cfg.cellspacing=this.cellspacing;
5336 cfg.frame=this.frame;
5339 cfg.rules=this.rules;
5341 if (this.sortable) {
5342 cfg.sortable=this.sortable;
5345 cfg.summary=this.summary;
5348 cfg.width=this.width;
5351 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5354 if(this.store || this.cm){
5356 cfg.cn.push(this.renderHeader());
5359 cfg.cn.push(this.renderBody());
5362 cfg.cn.push(this.renderFooter());
5365 cfg.cls+= ' TableGrid';
5368 return { cn : [ cfg ] };
5371 initEvents : function()
5373 if(!this.store || !this.cm){
5377 //Roo.log('initEvents with ds!!!!');
5379 this.mainBody = this.el.select('tbody', true).first();
5384 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5385 e.on('click', _this.sort, _this);
5388 this.el.on("click", this.onClick, this);
5389 this.el.on("dblclick", this.onDblClick, this);
5391 // why is this done????? = it breaks dialogs??
5392 //this.parent().el.setStyle('position', 'relative');
5396 this.footer.parentId = this.id;
5397 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5400 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5402 this.store.on('load', this.onLoad, this);
5403 this.store.on('beforeload', this.onBeforeLoad, this);
5404 this.store.on('update', this.onUpdate, this);
5405 this.store.on('add', this.onAdd, this);
5409 onMouseover : function(e, el)
5411 var cell = Roo.get(el);
5417 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5418 cell = cell.findParent('td', false, true);
5421 var row = cell.findParent('tr', false, true);
5422 var cellIndex = cell.dom.cellIndex;
5423 var rowIndex = row.dom.rowIndex - 1; // start from 0
5425 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5429 onMouseout : function(e, el)
5431 var cell = Roo.get(el);
5437 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5438 cell = cell.findParent('td', false, true);
5441 var row = cell.findParent('tr', false, true);
5442 var cellIndex = cell.dom.cellIndex;
5443 var rowIndex = row.dom.rowIndex - 1; // start from 0
5445 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5449 onClick : function(e, el)
5451 var cell = Roo.get(el);
5453 if(!cell || (!this.CellSelection && !this.RowSelection)){
5457 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5458 cell = cell.findParent('td', false, true);
5461 if(!cell || typeof(cell) == 'undefined'){
5465 var row = cell.findParent('tr', false, true);
5467 if(!row || typeof(row) == 'undefined'){
5471 var cellIndex = cell.dom.cellIndex;
5472 var rowIndex = this.getRowIndex(row);
5474 if(this.CellSelection){
5475 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5478 if(this.RowSelection){
5479 this.fireEvent('rowclick', this, row, rowIndex, e);
5485 onDblClick : function(e,el)
5487 var cell = Roo.get(el);
5489 if(!cell || (!this.CellSelection && !this.RowSelection)){
5493 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5494 cell = cell.findParent('td', false, true);
5497 if(!cell || typeof(cell) == 'undefined'){
5501 var row = cell.findParent('tr', false, true);
5503 if(!row || typeof(row) == 'undefined'){
5507 var cellIndex = cell.dom.cellIndex;
5508 var rowIndex = this.getRowIndex(row);
5510 if(this.CellSelection){
5511 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5514 if(this.RowSelection){
5515 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5519 sort : function(e,el)
5521 var col = Roo.get(el);
5523 if(!col.hasClass('sortable')){
5527 var sort = col.attr('sort');
5530 if(col.hasClass('glyphicon-arrow-up')){
5534 this.store.sortInfo = {field : sort, direction : dir};
5537 Roo.log("calling footer first");
5538 this.footer.onClick('first');
5541 this.store.load({ params : { start : 0 } });
5545 renderHeader : function()
5554 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5556 var config = cm.config[i];
5561 html: cm.getColumnHeader(i)
5564 if(typeof(config.tooltip) != 'undefined'){
5565 c.tooltip = config.tooltip;
5568 if(typeof(config.colspan) != 'undefined'){
5569 c.colspan = config.colspan;
5572 if(typeof(config.hidden) != 'undefined' && config.hidden){
5573 c.style += ' display:none;';
5576 if(typeof(config.dataIndex) != 'undefined'){
5577 c.sort = config.dataIndex;
5580 if(typeof(config.sortable) != 'undefined' && config.sortable){
5584 if(typeof(config.align) != 'undefined' && config.align.length){
5585 c.style += ' text-align:' + config.align + ';';
5588 if(typeof(config.width) != 'undefined'){
5589 c.style += ' width:' + config.width + 'px;';
5592 if(typeof(config.cls) != 'undefined'){
5593 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5602 renderBody : function()
5612 colspan : this.cm.getColumnCount()
5622 renderFooter : function()
5632 colspan : this.cm.getColumnCount()
5646 Roo.log('ds onload');
5651 var ds = this.store;
5653 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5654 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5656 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5657 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5660 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5661 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5665 var tbody = this.mainBody;
5667 if(ds.getCount() > 0){
5668 ds.data.each(function(d,rowIndex){
5669 var row = this.renderRow(cm, ds, rowIndex);
5671 tbody.createChild(row);
5675 if(row.cellObjects.length){
5676 Roo.each(row.cellObjects, function(r){
5677 _this.renderCellObject(r);
5684 Roo.each(this.el.select('tbody td', true).elements, function(e){
5685 e.on('mouseover', _this.onMouseover, _this);
5688 Roo.each(this.el.select('tbody td', true).elements, function(e){
5689 e.on('mouseout', _this.onMouseout, _this);
5691 this.fireEvent('rowsrendered', this);
5692 //if(this.loadMask){
5693 // this.maskEl.hide();
5698 onUpdate : function(ds,record)
5700 this.refreshRow(record);
5703 onRemove : function(ds, record, index, isUpdate){
5704 if(isUpdate !== true){
5705 this.fireEvent("beforerowremoved", this, index, record);
5707 var bt = this.mainBody.dom;
5709 var rows = this.el.select('tbody > tr', true).elements;
5711 if(typeof(rows[index]) != 'undefined'){
5712 bt.removeChild(rows[index].dom);
5715 // if(bt.rows[index]){
5716 // bt.removeChild(bt.rows[index]);
5719 if(isUpdate !== true){
5720 //this.stripeRows(index);
5721 //this.syncRowHeights(index, index);
5723 this.fireEvent("rowremoved", this, index, record);
5727 onAdd : function(ds, records, rowIndex)
5729 //Roo.log('on Add called');
5730 // - note this does not handle multiple adding very well..
5731 var bt = this.mainBody.dom;
5732 for (var i =0 ; i < records.length;i++) {
5733 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5734 //Roo.log(records[i]);
5735 //Roo.log(this.store.getAt(rowIndex+i));
5736 this.insertRow(this.store, rowIndex + i, false);
5743 refreshRow : function(record){
5744 var ds = this.store, index;
5745 if(typeof record == 'number'){
5747 record = ds.getAt(index);
5749 index = ds.indexOf(record);
5751 this.insertRow(ds, index, true);
5752 this.onRemove(ds, record, index+1, true);
5753 //this.syncRowHeights(index, index);
5755 this.fireEvent("rowupdated", this, index, record);
5758 insertRow : function(dm, rowIndex, isUpdate){
5761 this.fireEvent("beforerowsinserted", this, rowIndex);
5763 //var s = this.getScrollState();
5764 var row = this.renderRow(this.cm, this.store, rowIndex);
5765 // insert before rowIndex..
5766 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5770 if(row.cellObjects.length){
5771 Roo.each(row.cellObjects, function(r){
5772 _this.renderCellObject(r);
5777 this.fireEvent("rowsinserted", this, rowIndex);
5778 //this.syncRowHeights(firstRow, lastRow);
5779 //this.stripeRows(firstRow);
5786 getRowDom : function(rowIndex)
5788 var rows = this.el.select('tbody > tr', true).elements;
5790 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5793 // returns the object tree for a tr..
5796 renderRow : function(cm, ds, rowIndex)
5799 var d = ds.getAt(rowIndex);
5806 var cellObjects = [];
5808 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5809 var config = cm.config[i];
5811 var renderer = cm.getRenderer(i);
5815 if(typeof(renderer) !== 'undefined'){
5816 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5818 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5819 // and are rendered into the cells after the row is rendered - using the id for the element.
5821 if(typeof(value) === 'object'){
5831 rowIndex : rowIndex,
5836 this.fireEvent('rowclass', this, rowcfg);
5840 cls : rowcfg.rowClass,
5842 html: (typeof(value) === 'object') ? '' : value
5849 if(typeof(config.colspan) != 'undefined'){
5850 td.colspan = config.colspan;
5853 if(typeof(config.hidden) != 'undefined' && config.hidden){
5854 td.style += ' display:none;';
5857 if(typeof(config.align) != 'undefined' && config.align.length){
5858 td.style += ' text-align:' + config.align + ';';
5861 if(typeof(config.width) != 'undefined'){
5862 td.style += ' width:' + config.width + 'px;';
5865 if(typeof(config.cursor) != 'undefined'){
5866 td.style += ' cursor:' + config.cursor + ';';
5869 if(typeof(config.cls) != 'undefined'){
5870 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
5877 row.cellObjects = cellObjects;
5885 onBeforeLoad : function()
5887 //Roo.log('ds onBeforeLoad');
5891 //if(this.loadMask){
5892 // this.maskEl.show();
5900 this.el.select('tbody', true).first().dom.innerHTML = '';
5903 * Show or hide a row.
5904 * @param {Number} rowIndex to show or hide
5905 * @param {Boolean} state hide
5907 setRowVisibility : function(rowIndex, state)
5909 var bt = this.mainBody.dom;
5911 var rows = this.el.select('tbody > tr', true).elements;
5913 if(typeof(rows[rowIndex]) == 'undefined'){
5916 rows[rowIndex].dom.style.display = state ? '' : 'none';
5920 getSelectionModel : function(){
5922 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5924 return this.selModel;
5927 * Render the Roo.bootstrap object from renderder
5929 renderCellObject : function(r)
5933 var t = r.cfg.render(r.container);
5936 Roo.each(r.cfg.cn, function(c){
5938 container: t.getChildContainer(),
5941 _this.renderCellObject(child);
5946 getRowIndex : function(row)
5950 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5973 * @class Roo.bootstrap.TableCell
5974 * @extends Roo.bootstrap.Component
5975 * Bootstrap TableCell class
5976 * @cfg {String} html cell contain text
5977 * @cfg {String} cls cell class
5978 * @cfg {String} tag cell tag (td|th) default td
5979 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5980 * @cfg {String} align Aligns the content in a cell
5981 * @cfg {String} axis Categorizes cells
5982 * @cfg {String} bgcolor Specifies the background color of a cell
5983 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5984 * @cfg {Number} colspan Specifies the number of columns a cell should span
5985 * @cfg {String} headers Specifies one or more header cells a cell is related to
5986 * @cfg {Number} height Sets the height of a cell
5987 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5988 * @cfg {Number} rowspan Sets the number of rows a cell should span
5989 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5990 * @cfg {String} valign Vertical aligns the content in a cell
5991 * @cfg {Number} width Specifies the width of a cell
5994 * Create a new TableCell
5995 * @param {Object} config The config object
5998 Roo.bootstrap.TableCell = function(config){
5999 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6002 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6022 getAutoCreate : function(){
6023 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6043 cfg.align=this.align
6049 cfg.bgcolor=this.bgcolor
6052 cfg.charoff=this.charoff
6055 cfg.colspan=this.colspan
6058 cfg.headers=this.headers
6061 cfg.height=this.height
6064 cfg.nowrap=this.nowrap
6067 cfg.rowspan=this.rowspan
6070 cfg.scope=this.scope
6073 cfg.valign=this.valign
6076 cfg.width=this.width
6095 * @class Roo.bootstrap.TableRow
6096 * @extends Roo.bootstrap.Component
6097 * Bootstrap TableRow class
6098 * @cfg {String} cls row class
6099 * @cfg {String} align Aligns the content in a table row
6100 * @cfg {String} bgcolor Specifies a background color for a table row
6101 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6102 * @cfg {String} valign Vertical aligns the content in a table row
6105 * Create a new TableRow
6106 * @param {Object} config The config object
6109 Roo.bootstrap.TableRow = function(config){
6110 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6113 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6121 getAutoCreate : function(){
6122 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6132 cfg.align = this.align;
6135 cfg.bgcolor = this.bgcolor;
6138 cfg.charoff = this.charoff;
6141 cfg.valign = this.valign;
6159 * @class Roo.bootstrap.TableBody
6160 * @extends Roo.bootstrap.Component
6161 * Bootstrap TableBody class
6162 * @cfg {String} cls element class
6163 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6164 * @cfg {String} align Aligns the content inside the element
6165 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6166 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6169 * Create a new TableBody
6170 * @param {Object} config The config object
6173 Roo.bootstrap.TableBody = function(config){
6174 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6177 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6185 getAutoCreate : function(){
6186 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6200 cfg.align = this.align;
6203 cfg.charoff = this.charoff;
6206 cfg.valign = this.valign;
6213 // initEvents : function()
6220 // this.store = Roo.factory(this.store, Roo.data);
6221 // this.store.on('load', this.onLoad, this);
6223 // this.store.load();
6227 // onLoad: function ()
6229 // this.fireEvent('load', this);
6239 * Ext JS Library 1.1.1
6240 * Copyright(c) 2006-2007, Ext JS, LLC.
6242 * Originally Released Under LGPL - original licence link has changed is not relivant.
6245 * <script type="text/javascript">
6248 // as we use this in bootstrap.
6249 Roo.namespace('Roo.form');
6251 * @class Roo.form.Action
6252 * Internal Class used to handle form actions
6254 * @param {Roo.form.BasicForm} el The form element or its id
6255 * @param {Object} config Configuration options
6260 // define the action interface
6261 Roo.form.Action = function(form, options){
6263 this.options = options || {};
6266 * Client Validation Failed
6269 Roo.form.Action.CLIENT_INVALID = 'client';
6271 * Server Validation Failed
6274 Roo.form.Action.SERVER_INVALID = 'server';
6276 * Connect to Server Failed
6279 Roo.form.Action.CONNECT_FAILURE = 'connect';
6281 * Reading Data from Server Failed
6284 Roo.form.Action.LOAD_FAILURE = 'load';
6286 Roo.form.Action.prototype = {
6288 failureType : undefined,
6289 response : undefined,
6293 run : function(options){
6298 success : function(response){
6303 handleResponse : function(response){
6307 // default connection failure
6308 failure : function(response){
6310 this.response = response;
6311 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6312 this.form.afterAction(this, false);
6315 processResponse : function(response){
6316 this.response = response;
6317 if(!response.responseText){
6320 this.result = this.handleResponse(response);
6324 // utility functions used internally
6325 getUrl : function(appendParams){
6326 var url = this.options.url || this.form.url || this.form.el.dom.action;
6328 var p = this.getParams();
6330 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6336 getMethod : function(){
6337 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6340 getParams : function(){
6341 var bp = this.form.baseParams;
6342 var p = this.options.params;
6344 if(typeof p == "object"){
6345 p = Roo.urlEncode(Roo.applyIf(p, bp));
6346 }else if(typeof p == 'string' && bp){
6347 p += '&' + Roo.urlEncode(bp);
6350 p = Roo.urlEncode(bp);
6355 createCallback : function(){
6357 success: this.success,
6358 failure: this.failure,
6360 timeout: (this.form.timeout*1000),
6361 upload: this.form.fileUpload ? this.success : undefined
6366 Roo.form.Action.Submit = function(form, options){
6367 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6370 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6373 haveProgress : false,
6374 uploadComplete : false,
6376 // uploadProgress indicator.
6377 uploadProgress : function()
6379 if (!this.form.progressUrl) {
6383 if (!this.haveProgress) {
6384 Roo.MessageBox.progress("Uploading", "Uploading");
6386 if (this.uploadComplete) {
6387 Roo.MessageBox.hide();
6391 this.haveProgress = true;
6393 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6395 var c = new Roo.data.Connection();
6397 url : this.form.progressUrl,
6402 success : function(req){
6403 //console.log(data);
6407 rdata = Roo.decode(req.responseText)
6409 Roo.log("Invalid data from server..");
6413 if (!rdata || !rdata.success) {
6415 Roo.MessageBox.alert(Roo.encode(rdata));
6418 var data = rdata.data;
6420 if (this.uploadComplete) {
6421 Roo.MessageBox.hide();
6426 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6427 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6430 this.uploadProgress.defer(2000,this);
6433 failure: function(data) {
6434 Roo.log('progress url failed ');
6445 // run get Values on the form, so it syncs any secondary forms.
6446 this.form.getValues();
6448 var o = this.options;
6449 var method = this.getMethod();
6450 var isPost = method == 'POST';
6451 if(o.clientValidation === false || this.form.isValid()){
6453 if (this.form.progressUrl) {
6454 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6455 (new Date() * 1) + '' + Math.random());
6460 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6461 form:this.form.el.dom,
6462 url:this.getUrl(!isPost),
6464 params:isPost ? this.getParams() : null,
6465 isUpload: this.form.fileUpload
6468 this.uploadProgress();
6470 }else if (o.clientValidation !== false){ // client validation failed
6471 this.failureType = Roo.form.Action.CLIENT_INVALID;
6472 this.form.afterAction(this, false);
6476 success : function(response)
6478 this.uploadComplete= true;
6479 if (this.haveProgress) {
6480 Roo.MessageBox.hide();
6484 var result = this.processResponse(response);
6485 if(result === true || result.success){
6486 this.form.afterAction(this, true);
6490 this.form.markInvalid(result.errors);
6491 this.failureType = Roo.form.Action.SERVER_INVALID;
6493 this.form.afterAction(this, false);
6495 failure : function(response)
6497 this.uploadComplete= true;
6498 if (this.haveProgress) {
6499 Roo.MessageBox.hide();
6502 this.response = response;
6503 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6504 this.form.afterAction(this, false);
6507 handleResponse : function(response){
6508 if(this.form.errorReader){
6509 var rs = this.form.errorReader.read(response);
6512 for(var i = 0, len = rs.records.length; i < len; i++) {
6513 var r = rs.records[i];
6517 if(errors.length < 1){
6521 success : rs.success,
6527 ret = Roo.decode(response.responseText);
6531 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6541 Roo.form.Action.Load = function(form, options){
6542 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6543 this.reader = this.form.reader;
6546 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6551 Roo.Ajax.request(Roo.apply(
6552 this.createCallback(), {
6553 method:this.getMethod(),
6554 url:this.getUrl(false),
6555 params:this.getParams()
6559 success : function(response){
6561 var result = this.processResponse(response);
6562 if(result === true || !result.success || !result.data){
6563 this.failureType = Roo.form.Action.LOAD_FAILURE;
6564 this.form.afterAction(this, false);
6567 this.form.clearInvalid();
6568 this.form.setValues(result.data);
6569 this.form.afterAction(this, true);
6572 handleResponse : function(response){
6573 if(this.form.reader){
6574 var rs = this.form.reader.read(response);
6575 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6577 success : rs.success,
6581 return Roo.decode(response.responseText);
6585 Roo.form.Action.ACTION_TYPES = {
6586 'load' : Roo.form.Action.Load,
6587 'submit' : Roo.form.Action.Submit
6596 * @class Roo.bootstrap.Form
6597 * @extends Roo.bootstrap.Component
6598 * Bootstrap Form class
6599 * @cfg {String} method GET | POST (default POST)
6600 * @cfg {String} labelAlign top | left (default top)
6601 * @cfg {String} align left | right - for navbars
6602 * @cfg {Boolean} loadMask load mask when submit (default true)
6607 * @param {Object} config The config object
6611 Roo.bootstrap.Form = function(config){
6612 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6615 * @event clientvalidation
6616 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6617 * @param {Form} this
6618 * @param {Boolean} valid true if the form has passed client-side validation
6620 clientvalidation: true,
6622 * @event beforeaction
6623 * Fires before any action is performed. Return false to cancel the action.
6624 * @param {Form} this
6625 * @param {Action} action The action to be performed
6629 * @event actionfailed
6630 * Fires when an action fails.
6631 * @param {Form} this
6632 * @param {Action} action The action that failed
6634 actionfailed : true,
6636 * @event actioncomplete
6637 * Fires when an action is completed.
6638 * @param {Form} this
6639 * @param {Action} action The action that completed
6641 actioncomplete : true
6646 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6649 * @cfg {String} method
6650 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6655 * The URL to use for form actions if one isn't supplied in the action options.
6658 * @cfg {Boolean} fileUpload
6659 * Set to true if this form is a file upload.
6663 * @cfg {Object} baseParams
6664 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6668 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6672 * @cfg {Sting} align (left|right) for navbar forms
6677 activeAction : null,
6680 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6681 * element by passing it or its id or mask the form itself by passing in true.
6684 waitMsgTarget : false,
6688 getAutoCreate : function(){
6692 method : this.method || 'POST',
6693 id : this.id || Roo.id(),
6696 if (this.parent().xtype.match(/^Nav/)) {
6697 cfg.cls = 'navbar-form navbar-' + this.align;
6701 if (this.labelAlign == 'left' ) {
6702 cfg.cls += ' form-horizontal';
6708 initEvents : function()
6710 this.el.on('submit', this.onSubmit, this);
6711 // this was added as random key presses on the form where triggering form submit.
6712 this.el.on('keypress', function(e) {
6713 if (e.getCharCode() != 13) {
6716 // we might need to allow it for textareas.. and some other items.
6717 // check e.getTarget().
6719 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6723 Roo.log("keypress blocked");
6731 onSubmit : function(e){
6736 * Returns true if client-side validation on the form is successful.
6739 isValid : function(){
6740 var items = this.getItems();
6742 items.each(function(f){
6751 * Returns true if any fields in this form have changed since their original load.
6754 isDirty : function(){
6756 var items = this.getItems();
6757 items.each(function(f){
6767 * Performs a predefined action (submit or load) or custom actions you define on this form.
6768 * @param {String} actionName The name of the action type
6769 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6770 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6771 * accept other config options):
6773 Property Type Description
6774 ---------------- --------------- ----------------------------------------------------------------------------------
6775 url String The url for the action (defaults to the form's url)
6776 method String The form method to use (defaults to the form's method, or POST if not defined)
6777 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6778 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6779 validate the form on the client (defaults to false)
6781 * @return {BasicForm} this
6783 doAction : function(action, options){
6784 if(typeof action == 'string'){
6785 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6787 if(this.fireEvent('beforeaction', this, action) !== false){
6788 this.beforeAction(action);
6789 action.run.defer(100, action);
6795 beforeAction : function(action){
6796 var o = action.options;
6799 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6801 // not really supported yet.. ??
6803 //if(this.waitMsgTarget === true){
6804 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6805 //}else if(this.waitMsgTarget){
6806 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6807 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6809 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6815 afterAction : function(action, success){
6816 this.activeAction = null;
6817 var o = action.options;
6819 //if(this.waitMsgTarget === true){
6821 //}else if(this.waitMsgTarget){
6822 // this.waitMsgTarget.unmask();
6824 // Roo.MessageBox.updateProgress(1);
6825 // Roo.MessageBox.hide();
6832 Roo.callback(o.success, o.scope, [this, action]);
6833 this.fireEvent('actioncomplete', this, action);
6837 // failure condition..
6838 // we have a scenario where updates need confirming.
6839 // eg. if a locking scenario exists..
6840 // we look for { errors : { needs_confirm : true }} in the response.
6842 (typeof(action.result) != 'undefined') &&
6843 (typeof(action.result.errors) != 'undefined') &&
6844 (typeof(action.result.errors.needs_confirm) != 'undefined')
6847 Roo.log("not supported yet");
6850 Roo.MessageBox.confirm(
6851 "Change requires confirmation",
6852 action.result.errorMsg,
6857 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6867 Roo.callback(o.failure, o.scope, [this, action]);
6868 // show an error message if no failed handler is set..
6869 if (!this.hasListener('actionfailed')) {
6870 Roo.log("need to add dialog support");
6872 Roo.MessageBox.alert("Error",
6873 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6874 action.result.errorMsg :
6875 "Saving Failed, please check your entries or try again"
6880 this.fireEvent('actionfailed', this, action);
6885 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6886 * @param {String} id The value to search for
6889 findField : function(id){
6890 var items = this.getItems();
6891 var field = items.get(id);
6893 items.each(function(f){
6894 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6901 return field || null;
6904 * Mark fields in this form invalid in bulk.
6905 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6906 * @return {BasicForm} this
6908 markInvalid : function(errors){
6909 if(errors instanceof Array){
6910 for(var i = 0, len = errors.length; i < len; i++){
6911 var fieldError = errors[i];
6912 var f = this.findField(fieldError.id);
6914 f.markInvalid(fieldError.msg);
6920 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6921 field.markInvalid(errors[id]);
6925 //Roo.each(this.childForms || [], function (f) {
6926 // f.markInvalid(errors);
6933 * Set values for fields in this form in bulk.
6934 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6935 * @return {BasicForm} this
6937 setValues : function(values){
6938 if(values instanceof Array){ // array of objects
6939 for(var i = 0, len = values.length; i < len; i++){
6941 var f = this.findField(v.id);
6943 f.setValue(v.value);
6944 if(this.trackResetOnLoad){
6945 f.originalValue = f.getValue();
6949 }else{ // object hash
6952 if(typeof values[id] != 'function' && (field = this.findField(id))){
6954 if (field.setFromData &&
6956 field.displayField &&
6957 // combos' with local stores can
6958 // be queried via setValue()
6959 // to set their value..
6960 (field.store && !field.store.isLocal)
6964 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6965 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6966 field.setFromData(sd);
6969 field.setValue(values[id]);
6973 if(this.trackResetOnLoad){
6974 field.originalValue = field.getValue();
6980 //Roo.each(this.childForms || [], function (f) {
6981 // f.setValues(values);
6988 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6989 * they are returned as an array.
6990 * @param {Boolean} asString
6993 getValues : function(asString){
6994 //if (this.childForms) {
6995 // copy values from the child forms
6996 // Roo.each(this.childForms, function (f) {
6997 // this.setValues(f.getValues());
7003 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7004 if(asString === true){
7007 return Roo.urlDecode(fs);
7011 * Returns the fields in this form as an object with key/value pairs.
7012 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7015 getFieldValues : function(with_hidden)
7017 var items = this.getItems();
7019 items.each(function(f){
7023 var v = f.getValue();
7024 if (f.inputType =='radio') {
7025 if (typeof(ret[f.getName()]) == 'undefined') {
7026 ret[f.getName()] = ''; // empty..
7029 if (!f.el.dom.checked) {
7037 // not sure if this supported any more..
7038 if ((typeof(v) == 'object') && f.getRawValue) {
7039 v = f.getRawValue() ; // dates..
7041 // combo boxes where name != hiddenName...
7042 if (f.name != f.getName()) {
7043 ret[f.name] = f.getRawValue();
7045 ret[f.getName()] = v;
7052 * Clears all invalid messages in this form.
7053 * @return {BasicForm} this
7055 clearInvalid : function(){
7056 var items = this.getItems();
7058 items.each(function(f){
7069 * @return {BasicForm} this
7072 var items = this.getItems();
7073 items.each(function(f){
7077 Roo.each(this.childForms || [], function (f) {
7084 getItems : function()
7086 var r=new Roo.util.MixedCollection(false, function(o){
7087 return o.id || (o.id = Roo.id());
7089 var iter = function(el) {
7096 Roo.each(el.items,function(e) {
7116 * Ext JS Library 1.1.1
7117 * Copyright(c) 2006-2007, Ext JS, LLC.
7119 * Originally Released Under LGPL - original licence link has changed is not relivant.
7122 * <script type="text/javascript">
7125 * @class Roo.form.VTypes
7126 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7129 Roo.form.VTypes = function(){
7130 // closure these in so they are only created once.
7131 var alpha = /^[a-zA-Z_]+$/;
7132 var alphanum = /^[a-zA-Z0-9_]+$/;
7133 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7134 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7136 // All these messages and functions are configurable
7139 * The function used to validate email addresses
7140 * @param {String} value The email address
7142 'email' : function(v){
7143 return email.test(v);
7146 * The error text to display when the email validation function returns false
7149 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7151 * The keystroke filter mask to be applied on email input
7154 'emailMask' : /[a-z0-9_\.\-@]/i,
7157 * The function used to validate URLs
7158 * @param {String} value The URL
7160 'url' : function(v){
7164 * The error text to display when the url validation function returns false
7167 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7170 * The function used to validate alpha values
7171 * @param {String} value The value
7173 'alpha' : function(v){
7174 return alpha.test(v);
7177 * The error text to display when the alpha validation function returns false
7180 'alphaText' : 'This field should only contain letters and _',
7182 * The keystroke filter mask to be applied on alpha input
7185 'alphaMask' : /[a-z_]/i,
7188 * The function used to validate alphanumeric values
7189 * @param {String} value The value
7191 'alphanum' : function(v){
7192 return alphanum.test(v);
7195 * The error text to display when the alphanumeric validation function returns false
7198 'alphanumText' : 'This field should only contain letters, numbers and _',
7200 * The keystroke filter mask to be applied on alphanumeric input
7203 'alphanumMask' : /[a-z0-9_]/i
7213 * @class Roo.bootstrap.Input
7214 * @extends Roo.bootstrap.Component
7215 * Bootstrap Input class
7216 * @cfg {Boolean} disabled is it disabled
7217 * @cfg {String} fieldLabel - the label associated
7218 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7219 * @cfg {String} name name of the input
7220 * @cfg {string} fieldLabel - the label associated
7221 * @cfg {string} inputType - input / file submit ...
7222 * @cfg {string} placeholder - placeholder to put in text.
7223 * @cfg {string} before - input group add on before
7224 * @cfg {string} after - input group add on after
7225 * @cfg {string} size - (lg|sm) or leave empty..
7226 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7227 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7228 * @cfg {Number} md colspan out of 12 for computer-sized screens
7229 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7230 * @cfg {string} value default value of the input
7231 * @cfg {Number} labelWidth set the width of label (0-12)
7232 * @cfg {String} labelAlign (top|left)
7233 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7234 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7236 * @cfg {String} align (left|center|right) Default left
7241 * Create a new Input
7242 * @param {Object} config The config object
7245 Roo.bootstrap.Input = function(config){
7246 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7251 * Fires when this field receives input focus.
7252 * @param {Roo.form.Field} this
7257 * Fires when this field loses input focus.
7258 * @param {Roo.form.Field} this
7263 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7264 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7265 * @param {Roo.form.Field} this
7266 * @param {Roo.EventObject} e The event object
7271 * Fires just before the field blurs if the field value has changed.
7272 * @param {Roo.form.Field} this
7273 * @param {Mixed} newValue The new value
7274 * @param {Mixed} oldValue The original value
7279 * Fires after the field has been marked as invalid.
7280 * @param {Roo.form.Field} this
7281 * @param {String} msg The validation message
7286 * Fires after the field has been validated with no errors.
7287 * @param {Roo.form.Field} this
7292 * Fires after the key up
7293 * @param {Roo.form.Field} this
7294 * @param {Roo.EventObject} e The event Object
7300 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7302 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7303 automatic validation (defaults to "keyup").
7305 validationEvent : "keyup",
7307 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7309 validateOnBlur : true,
7311 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7313 validationDelay : 250,
7315 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7317 focusClass : "x-form-focus", // not needed???
7321 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7323 invalidClass : "has-warning",
7326 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7328 validClass : "has-success",
7331 * @cfg {Boolean} hasFeedback (true|false) default true
7336 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7338 invalidFeedbackClass : "glyphicon-warning-sign",
7341 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7343 validFeedbackClass : "glyphicon-ok",
7346 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7348 selectOnFocus : false,
7351 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7355 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7360 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7362 disableKeyFilter : false,
7365 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7369 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7373 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7375 blankText : "This field is required",
7378 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7382 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7384 maxLength : Number.MAX_VALUE,
7386 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7388 minLengthText : "The minimum length for this field is {0}",
7390 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7392 maxLengthText : "The maximum length for this field is {0}",
7396 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7397 * If available, this function will be called only after the basic validators all return true, and will be passed the
7398 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7402 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7403 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7404 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7408 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7412 autocomplete: false,
7431 formatedValue : false,
7433 parentLabelAlign : function()
7436 while (parent.parent()) {
7437 parent = parent.parent();
7438 if (typeof(parent.labelAlign) !='undefined') {
7439 return parent.labelAlign;
7446 getAutoCreate : function(){
7448 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7454 if(this.inputType != 'hidden'){
7455 cfg.cls = 'form-group' //input-group
7461 type : this.inputType,
7463 cls : 'form-control',
7464 placeholder : this.placeholder || '',
7465 autocomplete : this.autocomplete || 'new-password'
7470 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7473 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7474 input.maxLength = this.maxLength;
7477 if (this.disabled) {
7478 input.disabled=true;
7481 if (this.readOnly) {
7482 input.readonly=true;
7486 input.name = this.name;
7489 input.cls += ' input-' + this.size;
7492 ['xs','sm','md','lg'].map(function(size){
7493 if (settings[size]) {
7494 cfg.cls += ' col-' + size + '-' + settings[size];
7498 var inputblock = input;
7502 cls: 'glyphicon form-control-feedback'
7505 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7508 cls : 'has-feedback',
7516 if (this.before || this.after) {
7519 cls : 'input-group',
7523 if (this.before && typeof(this.before) == 'string') {
7525 inputblock.cn.push({
7527 cls : 'roo-input-before input-group-addon',
7531 if (this.before && typeof(this.before) == 'object') {
7532 this.before = Roo.factory(this.before);
7533 Roo.log(this.before);
7534 inputblock.cn.push({
7536 cls : 'roo-input-before input-group-' +
7537 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7541 inputblock.cn.push(input);
7543 if (this.after && typeof(this.after) == 'string') {
7544 inputblock.cn.push({
7546 cls : 'roo-input-after input-group-addon',
7550 if (this.after && typeof(this.after) == 'object') {
7551 this.after = Roo.factory(this.after);
7552 Roo.log(this.after);
7553 inputblock.cn.push({
7555 cls : 'roo-input-after input-group-' +
7556 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7560 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7561 inputblock.cls += ' has-feedback';
7562 inputblock.cn.push(feedback);
7566 if (align ==='left' && this.fieldLabel.length) {
7567 Roo.log("left and has label");
7573 cls : 'control-label col-sm-' + this.labelWidth,
7574 html : this.fieldLabel
7578 cls : "col-sm-" + (12 - this.labelWidth),
7585 } else if ( this.fieldLabel.length) {
7591 //cls : 'input-group-addon',
7592 html : this.fieldLabel
7602 Roo.log(" no label && no align");
7611 Roo.log('input-parentType: ' + this.parentType);
7613 if (this.parentType === 'Navbar' && this.parent().bar) {
7614 cfg.cls += ' navbar-form';
7622 * return the real input element.
7624 inputEl: function ()
7626 return this.el.select('input.form-control',true).first();
7629 tooltipEl : function()
7631 return this.inputEl();
7634 setDisabled : function(v)
7636 var i = this.inputEl().dom;
7638 i.removeAttribute('disabled');
7642 i.setAttribute('disabled','true');
7644 initEvents : function()
7647 this.inputEl().on("keydown" , this.fireKey, this);
7648 this.inputEl().on("focus", this.onFocus, this);
7649 this.inputEl().on("blur", this.onBlur, this);
7651 this.inputEl().relayEvent('keyup', this);
7653 // reference to original value for reset
7654 this.originalValue = this.getValue();
7655 //Roo.form.TextField.superclass.initEvents.call(this);
7656 if(this.validationEvent == 'keyup'){
7657 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7658 this.inputEl().on('keyup', this.filterValidation, this);
7660 else if(this.validationEvent !== false){
7661 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7664 if(this.selectOnFocus){
7665 this.on("focus", this.preFocus, this);
7668 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7669 this.inputEl().on("keypress", this.filterKeys, this);
7672 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7673 this.el.on("click", this.autoSize, this);
7676 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7677 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7680 if (typeof(this.before) == 'object') {
7681 this.before.render(this.el.select('.roo-input-before',true).first());
7683 if (typeof(this.after) == 'object') {
7684 this.after.render(this.el.select('.roo-input-after',true).first());
7689 filterValidation : function(e){
7690 if(!e.isNavKeyPress()){
7691 this.validationTask.delay(this.validationDelay);
7695 * Validates the field value
7696 * @return {Boolean} True if the value is valid, else false
7698 validate : function(){
7699 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7700 if(this.disabled || this.validateValue(this.getRawValue())){
7711 * Validates a value according to the field's validation rules and marks the field as invalid
7712 * if the validation fails
7713 * @param {Mixed} value The value to validate
7714 * @return {Boolean} True if the value is valid, else false
7716 validateValue : function(value){
7717 if(value.length < 1) { // if it's blank
7718 if(this.allowBlank){
7724 if(value.length < this.minLength){
7727 if(value.length > this.maxLength){
7731 var vt = Roo.form.VTypes;
7732 if(!vt[this.vtype](value, this)){
7736 if(typeof this.validator == "function"){
7737 var msg = this.validator(value);
7743 if(this.regex && !this.regex.test(value)){
7753 fireKey : function(e){
7754 //Roo.log('field ' + e.getKey());
7755 if(e.isNavKeyPress()){
7756 this.fireEvent("specialkey", this, e);
7759 focus : function (selectText){
7761 this.inputEl().focus();
7762 if(selectText === true){
7763 this.inputEl().dom.select();
7769 onFocus : function(){
7770 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7771 // this.el.addClass(this.focusClass);
7774 this.hasFocus = true;
7775 this.startValue = this.getValue();
7776 this.fireEvent("focus", this);
7780 beforeBlur : Roo.emptyFn,
7784 onBlur : function(){
7786 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7787 //this.el.removeClass(this.focusClass);
7789 this.hasFocus = false;
7790 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7793 var v = this.getValue();
7794 if(String(v) !== String(this.startValue)){
7795 this.fireEvent('change', this, v, this.startValue);
7797 this.fireEvent("blur", this);
7801 * Resets the current field value to the originally loaded value and clears any validation messages
7804 this.setValue(this.originalValue);
7808 * Returns the name of the field
7809 * @return {Mixed} name The name field
7811 getName: function(){
7815 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7816 * @return {Mixed} value The field value
7818 getValue : function(){
7820 var v = this.inputEl().getValue();
7825 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7826 * @return {Mixed} value The field value
7828 getRawValue : function(){
7829 var v = this.inputEl().getValue();
7835 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7836 * @param {Mixed} value The value to set
7838 setRawValue : function(v){
7839 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7842 selectText : function(start, end){
7843 var v = this.getRawValue();
7845 start = start === undefined ? 0 : start;
7846 end = end === undefined ? v.length : end;
7847 var d = this.inputEl().dom;
7848 if(d.setSelectionRange){
7849 d.setSelectionRange(start, end);
7850 }else if(d.createTextRange){
7851 var range = d.createTextRange();
7852 range.moveStart("character", start);
7853 range.moveEnd("character", v.length-end);
7860 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7861 * @param {Mixed} value The value to set
7863 setValue : function(v){
7866 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7872 processValue : function(value){
7873 if(this.stripCharsRe){
7874 var newValue = value.replace(this.stripCharsRe, '');
7875 if(newValue !== value){
7876 this.setRawValue(newValue);
7883 preFocus : function(){
7885 if(this.selectOnFocus){
7886 this.inputEl().dom.select();
7889 filterKeys : function(e){
7891 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7894 var c = e.getCharCode(), cc = String.fromCharCode(c);
7895 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7898 if(!this.maskRe.test(cc)){
7903 * Clear any invalid styles/messages for this field
7905 clearInvalid : function(){
7907 if(!this.el || this.preventMark){ // not rendered
7910 this.el.removeClass(this.invalidClass);
7912 this.fireEvent('valid', this);
7916 * Mark this field as valid
7918 markValid : function(){
7919 if(!this.el || this.preventMark){ // not rendered
7923 this.el.removeClass([this.invalidClass, this.validClass]);
7925 if(this.disabled || this.allowBlank){
7929 this.el.addClass(this.validClass);
7931 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7933 var feedback = this.el.select('.form-control-feedback', true).first();
7936 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7937 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7942 this.fireEvent('valid', this);
7946 * Mark this field as invalid
7947 * @param {String} msg The validation message
7949 markInvalid : function(msg){
7950 if(!this.el || this.preventMark){ // not rendered
7954 this.el.removeClass([this.invalidClass, this.validClass]);
7956 if(this.disabled || this.allowBlank){
7960 this.el.addClass(this.invalidClass);
7962 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7964 var feedback = this.el.select('.form-control-feedback', true).first();
7967 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7969 if(this.getValue().length){
7970 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7977 this.fireEvent('invalid', this, msg);
7980 SafariOnKeyDown : function(event)
7982 // this is a workaround for a password hang bug on chrome/ webkit.
7984 var isSelectAll = false;
7986 if(this.inputEl().dom.selectionEnd > 0){
7987 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7989 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7990 event.preventDefault();
7995 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7997 event.preventDefault();
7998 // this is very hacky as keydown always get's upper case.
8000 var cc = String.fromCharCode(event.getCharCode());
8001 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8005 adjustWidth : function(tag, w){
8006 tag = tag.toLowerCase();
8007 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8008 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8012 if(tag == 'textarea'){
8015 }else if(Roo.isOpera){
8019 if(tag == 'textarea'){
8038 * @class Roo.bootstrap.TextArea
8039 * @extends Roo.bootstrap.Input
8040 * Bootstrap TextArea class
8041 * @cfg {Number} cols Specifies the visible width of a text area
8042 * @cfg {Number} rows Specifies the visible number of lines in a text area
8043 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8044 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8045 * @cfg {string} html text
8048 * Create a new TextArea
8049 * @param {Object} config The config object
8052 Roo.bootstrap.TextArea = function(config){
8053 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8057 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8067 getAutoCreate : function(){
8069 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8080 value : this.value || '',
8081 html: this.html || '',
8082 cls : 'form-control',
8083 placeholder : this.placeholder || ''
8087 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8088 input.maxLength = this.maxLength;
8092 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8096 input.cols = this.cols;
8099 if (this.readOnly) {
8100 input.readonly = true;
8104 input.name = this.name;
8108 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8112 ['xs','sm','md','lg'].map(function(size){
8113 if (settings[size]) {
8114 cfg.cls += ' col-' + size + '-' + settings[size];
8118 var inputblock = input;
8120 if(this.hasFeedback && !this.allowBlank){
8124 cls: 'glyphicon form-control-feedback'
8128 cls : 'has-feedback',
8137 if (this.before || this.after) {
8140 cls : 'input-group',
8144 inputblock.cn.push({
8146 cls : 'input-group-addon',
8151 inputblock.cn.push(input);
8153 if(this.hasFeedback && !this.allowBlank){
8154 inputblock.cls += ' has-feedback';
8155 inputblock.cn.push(feedback);
8159 inputblock.cn.push({
8161 cls : 'input-group-addon',
8168 if (align ==='left' && this.fieldLabel.length) {
8169 Roo.log("left and has label");
8175 cls : 'control-label col-sm-' + this.labelWidth,
8176 html : this.fieldLabel
8180 cls : "col-sm-" + (12 - this.labelWidth),
8187 } else if ( this.fieldLabel.length) {
8193 //cls : 'input-group-addon',
8194 html : this.fieldLabel
8204 Roo.log(" no label && no align");
8214 if (this.disabled) {
8215 input.disabled=true;
8222 * return the real textarea element.
8224 inputEl: function ()
8226 return this.el.select('textarea.form-control',true).first();
8234 * trigger field - base class for combo..
8239 * @class Roo.bootstrap.TriggerField
8240 * @extends Roo.bootstrap.Input
8241 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8242 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8243 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8244 * for which you can provide a custom implementation. For example:
8246 var trigger = new Roo.bootstrap.TriggerField();
8247 trigger.onTriggerClick = myTriggerFn;
8248 trigger.applyTo('my-field');
8251 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8252 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8253 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8254 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8255 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8258 * Create a new TriggerField.
8259 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8260 * to the base TextField)
8262 Roo.bootstrap.TriggerField = function(config){
8263 this.mimicing = false;
8264 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8267 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8269 * @cfg {String} triggerClass A CSS class to apply to the trigger
8272 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8276 /** @cfg {Boolean} grow @hide */
8277 /** @cfg {Number} growMin @hide */
8278 /** @cfg {Number} growMax @hide */
8284 autoSize: Roo.emptyFn,
8291 actionMode : 'wrap',
8296 getAutoCreate : function(){
8298 var align = this.labelAlign || this.parentLabelAlign();
8303 cls: 'form-group' //input-group
8310 type : this.inputType,
8311 cls : 'form-control',
8312 autocomplete: 'new-password',
8313 placeholder : this.placeholder || ''
8317 input.name = this.name;
8320 input.cls += ' input-' + this.size;
8323 if (this.disabled) {
8324 input.disabled=true;
8327 var inputblock = input;
8329 if(this.hasFeedback && !this.allowBlank){
8333 cls: 'glyphicon form-control-feedback'
8337 cls : 'has-feedback',
8345 if (this.before || this.after) {
8348 cls : 'input-group',
8352 inputblock.cn.push({
8354 cls : 'input-group-addon',
8359 inputblock.cn.push(input);
8361 if(this.hasFeedback && !this.allowBlank){
8362 inputblock.cls += ' has-feedback';
8363 inputblock.cn.push(feedback);
8367 inputblock.cn.push({
8369 cls : 'input-group-addon',
8382 cls: 'form-hidden-field'
8390 Roo.log('multiple');
8398 cls: 'form-hidden-field'
8402 cls: 'select2-choices',
8406 cls: 'select2-search-field',
8419 cls: 'select2-container input-group',
8424 // cls: 'typeahead typeahead-long dropdown-menu',
8425 // style: 'display:none'
8430 if(!this.multiple && this.showToggleBtn){
8436 if (this.caret != false) {
8439 cls: 'fa fa-' + this.caret
8446 cls : 'input-group-addon btn dropdown-toggle',
8451 cls: 'combobox-clear',
8465 combobox.cls += ' select2-container-multi';
8468 if (align ==='left' && this.fieldLabel.length) {
8470 Roo.log("left and has label");
8476 cls : 'control-label col-sm-' + this.labelWidth,
8477 html : this.fieldLabel
8481 cls : "col-sm-" + (12 - this.labelWidth),
8488 } else if ( this.fieldLabel.length) {
8494 //cls : 'input-group-addon',
8495 html : this.fieldLabel
8505 Roo.log(" no label && no align");
8512 ['xs','sm','md','lg'].map(function(size){
8513 if (settings[size]) {
8514 cfg.cls += ' col-' + size + '-' + settings[size];
8525 onResize : function(w, h){
8526 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8527 // if(typeof w == 'number'){
8528 // var x = w - this.trigger.getWidth();
8529 // this.inputEl().setWidth(this.adjustWidth('input', x));
8530 // this.trigger.setStyle('left', x+'px');
8535 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8538 getResizeEl : function(){
8539 return this.inputEl();
8543 getPositionEl : function(){
8544 return this.inputEl();
8548 alignErrorIcon : function(){
8549 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8553 initEvents : function(){
8557 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8558 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8559 if(!this.multiple && this.showToggleBtn){
8560 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8561 if(this.hideTrigger){
8562 this.trigger.setDisplayed(false);
8564 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8568 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8571 //this.trigger.addClassOnOver('x-form-trigger-over');
8572 //this.trigger.addClassOnClick('x-form-trigger-click');
8575 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8579 createList : function()
8581 this.list = Roo.get(document.body).createChild({
8583 cls: 'typeahead typeahead-long dropdown-menu',
8584 style: 'display:none'
8587 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8592 initTrigger : function(){
8597 onDestroy : function(){
8599 this.trigger.removeAllListeners();
8600 // this.trigger.remove();
8603 // this.wrap.remove();
8605 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8609 onFocus : function(){
8610 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8613 this.wrap.addClass('x-trigger-wrap-focus');
8614 this.mimicing = true;
8615 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8616 if(this.monitorTab){
8617 this.el.on("keydown", this.checkTab, this);
8624 checkTab : function(e){
8625 if(e.getKey() == e.TAB){
8631 onBlur : function(){
8636 mimicBlur : function(e, t){
8638 if(!this.wrap.contains(t) && this.validateBlur()){
8645 triggerBlur : function(){
8646 this.mimicing = false;
8647 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8648 if(this.monitorTab){
8649 this.el.un("keydown", this.checkTab, this);
8651 //this.wrap.removeClass('x-trigger-wrap-focus');
8652 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8656 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8657 validateBlur : function(e, t){
8662 onDisable : function(){
8663 this.inputEl().dom.disabled = true;
8664 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8666 // this.wrap.addClass('x-item-disabled');
8671 onEnable : function(){
8672 this.inputEl().dom.disabled = false;
8673 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8675 // this.el.removeClass('x-item-disabled');
8680 onShow : function(){
8681 var ae = this.getActionEl();
8684 ae.dom.style.display = '';
8685 ae.dom.style.visibility = 'visible';
8691 onHide : function(){
8692 var ae = this.getActionEl();
8693 ae.dom.style.display = 'none';
8697 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8698 * by an implementing function.
8700 * @param {EventObject} e
8702 onTriggerClick : Roo.emptyFn
8706 * Ext JS Library 1.1.1
8707 * Copyright(c) 2006-2007, Ext JS, LLC.
8709 * Originally Released Under LGPL - original licence link has changed is not relivant.
8712 * <script type="text/javascript">
8717 * @class Roo.data.SortTypes
8719 * Defines the default sorting (casting?) comparison functions used when sorting data.
8721 Roo.data.SortTypes = {
8723 * Default sort that does nothing
8724 * @param {Mixed} s The value being converted
8725 * @return {Mixed} The comparison value
8732 * The regular expression used to strip tags
8736 stripTagsRE : /<\/?[^>]+>/gi,
8739 * Strips all HTML tags to sort on text only
8740 * @param {Mixed} s The value being converted
8741 * @return {String} The comparison value
8743 asText : function(s){
8744 return String(s).replace(this.stripTagsRE, "");
8748 * Strips all HTML tags to sort on text only - Case insensitive
8749 * @param {Mixed} s The value being converted
8750 * @return {String} The comparison value
8752 asUCText : function(s){
8753 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8757 * Case insensitive string
8758 * @param {Mixed} s The value being converted
8759 * @return {String} The comparison value
8761 asUCString : function(s) {
8762 return String(s).toUpperCase();
8767 * @param {Mixed} s The value being converted
8768 * @return {Number} The comparison value
8770 asDate : function(s) {
8774 if(s instanceof Date){
8777 return Date.parse(String(s));
8782 * @param {Mixed} s The value being converted
8783 * @return {Float} The comparison value
8785 asFloat : function(s) {
8786 var val = parseFloat(String(s).replace(/,/g, ""));
8787 if(isNaN(val)) val = 0;
8793 * @param {Mixed} s The value being converted
8794 * @return {Number} The comparison value
8796 asInt : function(s) {
8797 var val = parseInt(String(s).replace(/,/g, ""));
8798 if(isNaN(val)) val = 0;
8803 * Ext JS Library 1.1.1
8804 * Copyright(c) 2006-2007, Ext JS, LLC.
8806 * Originally Released Under LGPL - original licence link has changed is not relivant.
8809 * <script type="text/javascript">
8813 * @class Roo.data.Record
8814 * Instances of this class encapsulate both record <em>definition</em> information, and record
8815 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8816 * to access Records cached in an {@link Roo.data.Store} object.<br>
8818 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8819 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8822 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8824 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8825 * {@link #create}. The parameters are the same.
8826 * @param {Array} data An associative Array of data values keyed by the field name.
8827 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8828 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8829 * not specified an integer id is generated.
8831 Roo.data.Record = function(data, id){
8832 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8837 * Generate a constructor for a specific record layout.
8838 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8839 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8840 * Each field definition object may contain the following properties: <ul>
8841 * <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,
8842 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8843 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8844 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8845 * is being used, then this is a string containing the javascript expression to reference the data relative to
8846 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8847 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8848 * this may be omitted.</p></li>
8849 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8850 * <ul><li>auto (Default, implies no conversion)</li>
8855 * <li>date</li></ul></p></li>
8856 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8857 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8858 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8859 * by the Reader into an object that will be stored in the Record. It is passed the
8860 * following parameters:<ul>
8861 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8863 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8865 * <br>usage:<br><pre><code>
8866 var TopicRecord = Roo.data.Record.create(
8867 {name: 'title', mapping: 'topic_title'},
8868 {name: 'author', mapping: 'username'},
8869 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8870 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8871 {name: 'lastPoster', mapping: 'user2'},
8872 {name: 'excerpt', mapping: 'post_text'}
8875 var myNewRecord = new TopicRecord({
8876 title: 'Do my job please',
8879 lastPost: new Date(),
8880 lastPoster: 'Animal',
8881 excerpt: 'No way dude!'
8883 myStore.add(myNewRecord);
8888 Roo.data.Record.create = function(o){
8890 f.superclass.constructor.apply(this, arguments);
8892 Roo.extend(f, Roo.data.Record);
8893 var p = f.prototype;
8894 p.fields = new Roo.util.MixedCollection(false, function(field){
8897 for(var i = 0, len = o.length; i < len; i++){
8898 p.fields.add(new Roo.data.Field(o[i]));
8900 f.getField = function(name){
8901 return p.fields.get(name);
8906 Roo.data.Record.AUTO_ID = 1000;
8907 Roo.data.Record.EDIT = 'edit';
8908 Roo.data.Record.REJECT = 'reject';
8909 Roo.data.Record.COMMIT = 'commit';
8911 Roo.data.Record.prototype = {
8913 * Readonly flag - true if this record has been modified.
8922 join : function(store){
8927 * Set the named field to the specified value.
8928 * @param {String} name The name of the field to set.
8929 * @param {Object} value The value to set the field to.
8931 set : function(name, value){
8932 if(this.data[name] == value){
8939 if(typeof this.modified[name] == 'undefined'){
8940 this.modified[name] = this.data[name];
8942 this.data[name] = value;
8943 if(!this.editing && this.store){
8944 this.store.afterEdit(this);
8949 * Get the value of the named field.
8950 * @param {String} name The name of the field to get the value of.
8951 * @return {Object} The value of the field.
8953 get : function(name){
8954 return this.data[name];
8958 beginEdit : function(){
8959 this.editing = true;
8964 cancelEdit : function(){
8965 this.editing = false;
8966 delete this.modified;
8970 endEdit : function(){
8971 this.editing = false;
8972 if(this.dirty && this.store){
8973 this.store.afterEdit(this);
8978 * Usually called by the {@link Roo.data.Store} which owns the Record.
8979 * Rejects all changes made to the Record since either creation, or the last commit operation.
8980 * Modified fields are reverted to their original values.
8982 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8983 * of reject operations.
8985 reject : function(){
8986 var m = this.modified;
8988 if(typeof m[n] != "function"){
8989 this.data[n] = m[n];
8993 delete this.modified;
8994 this.editing = false;
8996 this.store.afterReject(this);
9001 * Usually called by the {@link Roo.data.Store} which owns the Record.
9002 * Commits all changes made to the Record since either creation, or the last commit operation.
9004 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9005 * of commit operations.
9007 commit : function(){
9009 delete this.modified;
9010 this.editing = false;
9012 this.store.afterCommit(this);
9017 hasError : function(){
9018 return this.error != null;
9022 clearError : function(){
9027 * Creates a copy of this record.
9028 * @param {String} id (optional) A new record id if you don't want to use this record's id
9031 copy : function(newId) {
9032 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9036 * Ext JS Library 1.1.1
9037 * Copyright(c) 2006-2007, Ext JS, LLC.
9039 * Originally Released Under LGPL - original licence link has changed is not relivant.
9042 * <script type="text/javascript">
9048 * @class Roo.data.Store
9049 * @extends Roo.util.Observable
9050 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9051 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9053 * 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
9054 * has no knowledge of the format of the data returned by the Proxy.<br>
9056 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9057 * instances from the data object. These records are cached and made available through accessor functions.
9059 * Creates a new Store.
9060 * @param {Object} config A config object containing the objects needed for the Store to access data,
9061 * and read the data into Records.
9063 Roo.data.Store = function(config){
9064 this.data = new Roo.util.MixedCollection(false);
9065 this.data.getKey = function(o){
9068 this.baseParams = {};
9075 "multisort" : "_multisort"
9078 if(config && config.data){
9079 this.inlineData = config.data;
9083 Roo.apply(this, config);
9085 if(this.reader){ // reader passed
9086 this.reader = Roo.factory(this.reader, Roo.data);
9087 this.reader.xmodule = this.xmodule || false;
9088 if(!this.recordType){
9089 this.recordType = this.reader.recordType;
9091 if(this.reader.onMetaChange){
9092 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9096 if(this.recordType){
9097 this.fields = this.recordType.prototype.fields;
9103 * @event datachanged
9104 * Fires when the data cache has changed, and a widget which is using this Store
9105 * as a Record cache should refresh its view.
9106 * @param {Store} this
9111 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9112 * @param {Store} this
9113 * @param {Object} meta The JSON metadata
9118 * Fires when Records have been added to the Store
9119 * @param {Store} this
9120 * @param {Roo.data.Record[]} records The array of Records added
9121 * @param {Number} index The index at which the record(s) were added
9126 * Fires when a Record has been removed from the Store
9127 * @param {Store} this
9128 * @param {Roo.data.Record} record The Record that was removed
9129 * @param {Number} index The index at which the record was removed
9134 * Fires when a Record has been updated
9135 * @param {Store} this
9136 * @param {Roo.data.Record} record The Record that was updated
9137 * @param {String} operation The update operation being performed. Value may be one of:
9139 Roo.data.Record.EDIT
9140 Roo.data.Record.REJECT
9141 Roo.data.Record.COMMIT
9147 * Fires when the data cache has been cleared.
9148 * @param {Store} this
9153 * Fires before a request is made for a new data object. If the beforeload handler returns false
9154 * the load action will be canceled.
9155 * @param {Store} this
9156 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9160 * @event beforeloadadd
9161 * Fires after a new set of Records has been loaded.
9162 * @param {Store} this
9163 * @param {Roo.data.Record[]} records The Records that were loaded
9164 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9166 beforeloadadd : true,
9169 * Fires after a new set of Records has been loaded, before they are added to the store.
9170 * @param {Store} this
9171 * @param {Roo.data.Record[]} records The Records that were loaded
9172 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9173 * @params {Object} return from reader
9177 * @event loadexception
9178 * Fires if an exception occurs in the Proxy during loading.
9179 * Called with the signature of the Proxy's "loadexception" event.
9180 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9183 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9184 * @param {Object} load options
9185 * @param {Object} jsonData from your request (normally this contains the Exception)
9187 loadexception : true
9191 this.proxy = Roo.factory(this.proxy, Roo.data);
9192 this.proxy.xmodule = this.xmodule || false;
9193 this.relayEvents(this.proxy, ["loadexception"]);
9195 this.sortToggle = {};
9196 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9198 Roo.data.Store.superclass.constructor.call(this);
9200 if(this.inlineData){
9201 this.loadData(this.inlineData);
9202 delete this.inlineData;
9206 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9208 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9209 * without a remote query - used by combo/forms at present.
9213 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9216 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9219 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9220 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9223 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9224 * on any HTTP request
9227 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9230 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9234 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9235 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9240 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9241 * loaded or when a record is removed. (defaults to false).
9243 pruneModifiedRecords : false,
9249 * Add Records to the Store and fires the add event.
9250 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9252 add : function(records){
9253 records = [].concat(records);
9254 for(var i = 0, len = records.length; i < len; i++){
9255 records[i].join(this);
9257 var index = this.data.length;
9258 this.data.addAll(records);
9259 this.fireEvent("add", this, records, index);
9263 * Remove a Record from the Store and fires the remove event.
9264 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9266 remove : function(record){
9267 var index = this.data.indexOf(record);
9268 this.data.removeAt(index);
9269 if(this.pruneModifiedRecords){
9270 this.modified.remove(record);
9272 this.fireEvent("remove", this, record, index);
9276 * Remove all Records from the Store and fires the clear event.
9278 removeAll : function(){
9280 if(this.pruneModifiedRecords){
9283 this.fireEvent("clear", this);
9287 * Inserts Records to the Store at the given index and fires the add event.
9288 * @param {Number} index The start index at which to insert the passed Records.
9289 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9291 insert : function(index, records){
9292 records = [].concat(records);
9293 for(var i = 0, len = records.length; i < len; i++){
9294 this.data.insert(index, records[i]);
9295 records[i].join(this);
9297 this.fireEvent("add", this, records, index);
9301 * Get the index within the cache of the passed Record.
9302 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9303 * @return {Number} The index of the passed Record. Returns -1 if not found.
9305 indexOf : function(record){
9306 return this.data.indexOf(record);
9310 * Get the index within the cache of the Record with the passed id.
9311 * @param {String} id The id of the Record to find.
9312 * @return {Number} The index of the Record. Returns -1 if not found.
9314 indexOfId : function(id){
9315 return this.data.indexOfKey(id);
9319 * Get the Record with the specified id.
9320 * @param {String} id The id of the Record to find.
9321 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9323 getById : function(id){
9324 return this.data.key(id);
9328 * Get the Record at the specified index.
9329 * @param {Number} index The index of the Record to find.
9330 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9332 getAt : function(index){
9333 return this.data.itemAt(index);
9337 * Returns a range of Records between specified indices.
9338 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9339 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9340 * @return {Roo.data.Record[]} An array of Records
9342 getRange : function(start, end){
9343 return this.data.getRange(start, end);
9347 storeOptions : function(o){
9348 o = Roo.apply({}, o);
9351 this.lastOptions = o;
9355 * Loads the Record cache from the configured Proxy using the configured Reader.
9357 * If using remote paging, then the first load call must specify the <em>start</em>
9358 * and <em>limit</em> properties in the options.params property to establish the initial
9359 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9361 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9362 * and this call will return before the new data has been loaded. Perform any post-processing
9363 * in a callback function, or in a "load" event handler.</strong>
9365 * @param {Object} options An object containing properties which control loading options:<ul>
9366 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9367 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9368 * passed the following arguments:<ul>
9369 * <li>r : Roo.data.Record[]</li>
9370 * <li>options: Options object from the load call</li>
9371 * <li>success: Boolean success indicator</li></ul></li>
9372 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9373 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9376 load : function(options){
9377 options = options || {};
9378 if(this.fireEvent("beforeload", this, options) !== false){
9379 this.storeOptions(options);
9380 var p = Roo.apply(options.params || {}, this.baseParams);
9381 // if meta was not loaded from remote source.. try requesting it.
9382 if (!this.reader.metaFromRemote) {
9385 if(this.sortInfo && this.remoteSort){
9386 var pn = this.paramNames;
9387 p[pn["sort"]] = this.sortInfo.field;
9388 p[pn["dir"]] = this.sortInfo.direction;
9390 if (this.multiSort) {
9391 var pn = this.paramNames;
9392 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9395 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9400 * Reloads the Record cache from the configured Proxy using the configured Reader and
9401 * the options from the last load operation performed.
9402 * @param {Object} options (optional) An object containing properties which may override the options
9403 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9404 * the most recently used options are reused).
9406 reload : function(options){
9407 this.load(Roo.applyIf(options||{}, this.lastOptions));
9411 // Called as a callback by the Reader during a load operation.
9412 loadRecords : function(o, options, success){
9413 if(!o || success === false){
9414 if(success !== false){
9415 this.fireEvent("load", this, [], options, o);
9417 if(options.callback){
9418 options.callback.call(options.scope || this, [], options, false);
9422 // if data returned failure - throw an exception.
9423 if (o.success === false) {
9424 // show a message if no listener is registered.
9425 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9426 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9428 // loadmask wil be hooked into this..
9429 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9432 var r = o.records, t = o.totalRecords || r.length;
9434 this.fireEvent("beforeloadadd", this, r, options, o);
9436 if(!options || options.add !== true){
9437 if(this.pruneModifiedRecords){
9440 for(var i = 0, len = r.length; i < len; i++){
9444 this.data = this.snapshot;
9445 delete this.snapshot;
9448 this.data.addAll(r);
9449 this.totalLength = t;
9451 this.fireEvent("datachanged", this);
9453 this.totalLength = Math.max(t, this.data.length+r.length);
9456 this.fireEvent("load", this, r, options, o);
9457 if(options.callback){
9458 options.callback.call(options.scope || this, r, options, true);
9464 * Loads data from a passed data block. A Reader which understands the format of the data
9465 * must have been configured in the constructor.
9466 * @param {Object} data The data block from which to read the Records. The format of the data expected
9467 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9468 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9470 loadData : function(o, append){
9471 var r = this.reader.readRecords(o);
9472 this.loadRecords(r, {add: append}, true);
9476 * Gets the number of cached records.
9478 * <em>If using paging, this may not be the total size of the dataset. If the data object
9479 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9480 * the data set size</em>
9482 getCount : function(){
9483 return this.data.length || 0;
9487 * Gets the total number of records in the dataset as returned by the server.
9489 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9490 * the dataset size</em>
9492 getTotalCount : function(){
9493 return this.totalLength || 0;
9497 * Returns the sort state of the Store as an object with two properties:
9499 field {String} The name of the field by which the Records are sorted
9500 direction {String} The sort order, "ASC" or "DESC"
9503 getSortState : function(){
9504 return this.sortInfo;
9508 applySort : function(){
9509 if(this.sortInfo && !this.remoteSort){
9510 var s = this.sortInfo, f = s.field;
9511 var st = this.fields.get(f).sortType;
9512 var fn = function(r1, r2){
9513 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9514 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9516 this.data.sort(s.direction, fn);
9517 if(this.snapshot && this.snapshot != this.data){
9518 this.snapshot.sort(s.direction, fn);
9524 * Sets the default sort column and order to be used by the next load operation.
9525 * @param {String} fieldName The name of the field to sort by.
9526 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9528 setDefaultSort : function(field, dir){
9529 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9534 * If remote sorting is used, the sort is performed on the server, and the cache is
9535 * reloaded. If local sorting is used, the cache is sorted internally.
9536 * @param {String} fieldName The name of the field to sort by.
9537 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9539 sort : function(fieldName, dir){
9540 var f = this.fields.get(fieldName);
9542 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9544 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9545 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9550 this.sortToggle[f.name] = dir;
9551 this.sortInfo = {field: f.name, direction: dir};
9552 if(!this.remoteSort){
9554 this.fireEvent("datachanged", this);
9556 this.load(this.lastOptions);
9561 * Calls the specified function for each of the Records in the cache.
9562 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9563 * Returning <em>false</em> aborts and exits the iteration.
9564 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9566 each : function(fn, scope){
9567 this.data.each(fn, scope);
9571 * Gets all records modified since the last commit. Modified records are persisted across load operations
9572 * (e.g., during paging).
9573 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9575 getModifiedRecords : function(){
9576 return this.modified;
9580 createFilterFn : function(property, value, anyMatch){
9581 if(!value.exec){ // not a regex
9582 value = String(value);
9583 if(value.length == 0){
9586 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9589 return value.test(r.data[property]);
9594 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9595 * @param {String} property A field on your records
9596 * @param {Number} start The record index to start at (defaults to 0)
9597 * @param {Number} end The last record index to include (defaults to length - 1)
9598 * @return {Number} The sum
9600 sum : function(property, start, end){
9601 var rs = this.data.items, v = 0;
9603 end = (end || end === 0) ? end : rs.length-1;
9605 for(var i = start; i <= end; i++){
9606 v += (rs[i].data[property] || 0);
9612 * Filter the records by a specified property.
9613 * @param {String} field A field on your records
9614 * @param {String/RegExp} value Either a string that the field
9615 * should start with or a RegExp to test against the field
9616 * @param {Boolean} anyMatch True to match any part not just the beginning
9618 filter : function(property, value, anyMatch){
9619 var fn = this.createFilterFn(property, value, anyMatch);
9620 return fn ? this.filterBy(fn) : this.clearFilter();
9624 * Filter by a function. The specified function will be called with each
9625 * record in this data source. If the function returns true the record is included,
9626 * otherwise it is filtered.
9627 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9628 * @param {Object} scope (optional) The scope of the function (defaults to this)
9630 filterBy : function(fn, scope){
9631 this.snapshot = this.snapshot || this.data;
9632 this.data = this.queryBy(fn, scope||this);
9633 this.fireEvent("datachanged", this);
9637 * Query the records by a specified property.
9638 * @param {String} field A field on your records
9639 * @param {String/RegExp} value Either a string that the field
9640 * should start with or a RegExp to test against the field
9641 * @param {Boolean} anyMatch True to match any part not just the beginning
9642 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9644 query : function(property, value, anyMatch){
9645 var fn = this.createFilterFn(property, value, anyMatch);
9646 return fn ? this.queryBy(fn) : this.data.clone();
9650 * Query by a function. The specified function will be called with each
9651 * record in this data source. If the function returns true the record is included
9653 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9654 * @param {Object} scope (optional) The scope of the function (defaults to this)
9655 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9657 queryBy : function(fn, scope){
9658 var data = this.snapshot || this.data;
9659 return data.filterBy(fn, scope||this);
9663 * Collects unique values for a particular dataIndex from this store.
9664 * @param {String} dataIndex The property to collect
9665 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9666 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9667 * @return {Array} An array of the unique values
9669 collect : function(dataIndex, allowNull, bypassFilter){
9670 var d = (bypassFilter === true && this.snapshot) ?
9671 this.snapshot.items : this.data.items;
9672 var v, sv, r = [], l = {};
9673 for(var i = 0, len = d.length; i < len; i++){
9674 v = d[i].data[dataIndex];
9676 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9685 * Revert to a view of the Record cache with no filtering applied.
9686 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9688 clearFilter : function(suppressEvent){
9689 if(this.snapshot && this.snapshot != this.data){
9690 this.data = this.snapshot;
9691 delete this.snapshot;
9692 if(suppressEvent !== true){
9693 this.fireEvent("datachanged", this);
9699 afterEdit : function(record){
9700 if(this.modified.indexOf(record) == -1){
9701 this.modified.push(record);
9703 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9707 afterReject : function(record){
9708 this.modified.remove(record);
9709 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9713 afterCommit : function(record){
9714 this.modified.remove(record);
9715 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9719 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9720 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9722 commitChanges : function(){
9723 var m = this.modified.slice(0);
9725 for(var i = 0, len = m.length; i < len; i++){
9731 * Cancel outstanding changes on all changed records.
9733 rejectChanges : function(){
9734 var m = this.modified.slice(0);
9736 for(var i = 0, len = m.length; i < len; i++){
9741 onMetaChange : function(meta, rtype, o){
9742 this.recordType = rtype;
9743 this.fields = rtype.prototype.fields;
9744 delete this.snapshot;
9745 this.sortInfo = meta.sortInfo || this.sortInfo;
9747 this.fireEvent('metachange', this, this.reader.meta);
9750 moveIndex : function(data, type)
9752 var index = this.indexOf(data);
9754 var newIndex = index + type;
9758 this.insert(newIndex, data);
9763 * Ext JS Library 1.1.1
9764 * Copyright(c) 2006-2007, Ext JS, LLC.
9766 * Originally Released Under LGPL - original licence link has changed is not relivant.
9769 * <script type="text/javascript">
9773 * @class Roo.data.SimpleStore
9774 * @extends Roo.data.Store
9775 * Small helper class to make creating Stores from Array data easier.
9776 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9777 * @cfg {Array} fields An array of field definition objects, or field name strings.
9778 * @cfg {Array} data The multi-dimensional array of data
9780 * @param {Object} config
9782 Roo.data.SimpleStore = function(config){
9783 Roo.data.SimpleStore.superclass.constructor.call(this, {
9785 reader: new Roo.data.ArrayReader({
9788 Roo.data.Record.create(config.fields)
9790 proxy : new Roo.data.MemoryProxy(config.data)
9794 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9796 * Ext JS Library 1.1.1
9797 * Copyright(c) 2006-2007, Ext JS, LLC.
9799 * Originally Released Under LGPL - original licence link has changed is not relivant.
9802 * <script type="text/javascript">
9807 * @extends Roo.data.Store
9808 * @class Roo.data.JsonStore
9809 * Small helper class to make creating Stores for JSON data easier. <br/>
9811 var store = new Roo.data.JsonStore({
9812 url: 'get-images.php',
9814 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9817 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9818 * JsonReader and HttpProxy (unless inline data is provided).</b>
9819 * @cfg {Array} fields An array of field definition objects, or field name strings.
9821 * @param {Object} config
9823 Roo.data.JsonStore = function(c){
9824 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9825 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9826 reader: new Roo.data.JsonReader(c, c.fields)
9829 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9831 * Ext JS Library 1.1.1
9832 * Copyright(c) 2006-2007, Ext JS, LLC.
9834 * Originally Released Under LGPL - original licence link has changed is not relivant.
9837 * <script type="text/javascript">
9841 Roo.data.Field = function(config){
9842 if(typeof config == "string"){
9843 config = {name: config};
9845 Roo.apply(this, config);
9851 var st = Roo.data.SortTypes;
9852 // named sortTypes are supported, here we look them up
9853 if(typeof this.sortType == "string"){
9854 this.sortType = st[this.sortType];
9857 // set default sortType for strings and dates
9861 this.sortType = st.asUCString;
9864 this.sortType = st.asDate;
9867 this.sortType = st.none;
9872 var stripRe = /[\$,%]/g;
9874 // prebuilt conversion function for this field, instead of
9875 // switching every time we're reading a value
9877 var cv, dateFormat = this.dateFormat;
9882 cv = function(v){ return v; };
9885 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9889 return v !== undefined && v !== null && v !== '' ?
9890 parseInt(String(v).replace(stripRe, ""), 10) : '';
9895 return v !== undefined && v !== null && v !== '' ?
9896 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9901 cv = function(v){ return v === true || v === "true" || v == 1; };
9908 if(v instanceof Date){
9912 if(dateFormat == "timestamp"){
9913 return new Date(v*1000);
9915 return Date.parseDate(v, dateFormat);
9917 var parsed = Date.parse(v);
9918 return parsed ? new Date(parsed) : null;
9927 Roo.data.Field.prototype = {
9935 * Ext JS Library 1.1.1
9936 * Copyright(c) 2006-2007, Ext JS, LLC.
9938 * Originally Released Under LGPL - original licence link has changed is not relivant.
9941 * <script type="text/javascript">
9944 // Base class for reading structured data from a data source. This class is intended to be
9945 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9948 * @class Roo.data.DataReader
9949 * Base class for reading structured data from a data source. This class is intended to be
9950 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9953 Roo.data.DataReader = function(meta, recordType){
9957 this.recordType = recordType instanceof Array ?
9958 Roo.data.Record.create(recordType) : recordType;
9961 Roo.data.DataReader.prototype = {
9963 * Create an empty record
9964 * @param {Object} data (optional) - overlay some values
9965 * @return {Roo.data.Record} record created.
9967 newRow : function(d) {
9969 this.recordType.prototype.fields.each(function(c) {
9971 case 'int' : da[c.name] = 0; break;
9972 case 'date' : da[c.name] = new Date(); break;
9973 case 'float' : da[c.name] = 0.0; break;
9974 case 'boolean' : da[c.name] = false; break;
9975 default : da[c.name] = ""; break;
9979 return new this.recordType(Roo.apply(da, d));
9984 * Ext JS Library 1.1.1
9985 * Copyright(c) 2006-2007, Ext JS, LLC.
9987 * Originally Released Under LGPL - original licence link has changed is not relivant.
9990 * <script type="text/javascript">
9994 * @class Roo.data.DataProxy
9995 * @extends Roo.data.Observable
9996 * This class is an abstract base class for implementations which provide retrieval of
9997 * unformatted data objects.<br>
9999 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10000 * (of the appropriate type which knows how to parse the data object) to provide a block of
10001 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10003 * Custom implementations must implement the load method as described in
10004 * {@link Roo.data.HttpProxy#load}.
10006 Roo.data.DataProxy = function(){
10009 * @event beforeload
10010 * Fires before a network request is made to retrieve a data object.
10011 * @param {Object} This DataProxy object.
10012 * @param {Object} params The params parameter to the load function.
10017 * Fires before the load method's callback is called.
10018 * @param {Object} This DataProxy object.
10019 * @param {Object} o The data object.
10020 * @param {Object} arg The callback argument object passed to the load function.
10024 * @event loadexception
10025 * Fires if an Exception occurs during data retrieval.
10026 * @param {Object} This DataProxy object.
10027 * @param {Object} o The data object.
10028 * @param {Object} arg The callback argument object passed to the load function.
10029 * @param {Object} e The Exception.
10031 loadexception : true
10033 Roo.data.DataProxy.superclass.constructor.call(this);
10036 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10039 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10043 * Ext JS Library 1.1.1
10044 * Copyright(c) 2006-2007, Ext JS, LLC.
10046 * Originally Released Under LGPL - original licence link has changed is not relivant.
10049 * <script type="text/javascript">
10052 * @class Roo.data.MemoryProxy
10053 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10054 * to the Reader when its load method is called.
10056 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10058 Roo.data.MemoryProxy = function(data){
10062 Roo.data.MemoryProxy.superclass.constructor.call(this);
10066 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10068 * Load data from the requested source (in this case an in-memory
10069 * data object passed to the constructor), read the data object into
10070 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10071 * process that block using the passed callback.
10072 * @param {Object} params This parameter is not used by the MemoryProxy class.
10073 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10074 * object into a block of Roo.data.Records.
10075 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10076 * The function must be passed <ul>
10077 * <li>The Record block object</li>
10078 * <li>The "arg" argument from the load function</li>
10079 * <li>A boolean success indicator</li>
10081 * @param {Object} scope The scope in which to call the callback
10082 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10084 load : function(params, reader, callback, scope, arg){
10085 params = params || {};
10088 result = reader.readRecords(this.data);
10090 this.fireEvent("loadexception", this, arg, null, e);
10091 callback.call(scope, null, arg, false);
10094 callback.call(scope, result, arg, true);
10098 update : function(params, records){
10103 * Ext JS Library 1.1.1
10104 * Copyright(c) 2006-2007, Ext JS, LLC.
10106 * Originally Released Under LGPL - original licence link has changed is not relivant.
10109 * <script type="text/javascript">
10112 * @class Roo.data.HttpProxy
10113 * @extends Roo.data.DataProxy
10114 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10115 * configured to reference a certain URL.<br><br>
10117 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10118 * from which the running page was served.<br><br>
10120 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10122 * Be aware that to enable the browser to parse an XML document, the server must set
10123 * the Content-Type header in the HTTP response to "text/xml".
10125 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10126 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10127 * will be used to make the request.
10129 Roo.data.HttpProxy = function(conn){
10130 Roo.data.HttpProxy.superclass.constructor.call(this);
10131 // is conn a conn config or a real conn?
10133 this.useAjax = !conn || !conn.events;
10137 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10138 // thse are take from connection...
10141 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10144 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10145 * extra parameters to each request made by this object. (defaults to undefined)
10148 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10149 * to each request made by this object. (defaults to undefined)
10152 * @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)
10155 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10158 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10164 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10168 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10169 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10170 * a finer-grained basis than the DataProxy events.
10172 getConnection : function(){
10173 return this.useAjax ? Roo.Ajax : this.conn;
10177 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10178 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10179 * process that block using the passed callback.
10180 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10181 * for the request to the remote server.
10182 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10183 * object into a block of Roo.data.Records.
10184 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10185 * The function must be passed <ul>
10186 * <li>The Record block object</li>
10187 * <li>The "arg" argument from the load function</li>
10188 * <li>A boolean success indicator</li>
10190 * @param {Object} scope The scope in which to call the callback
10191 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10193 load : function(params, reader, callback, scope, arg){
10194 if(this.fireEvent("beforeload", this, params) !== false){
10196 params : params || {},
10198 callback : callback,
10203 callback : this.loadResponse,
10207 Roo.applyIf(o, this.conn);
10208 if(this.activeRequest){
10209 Roo.Ajax.abort(this.activeRequest);
10211 this.activeRequest = Roo.Ajax.request(o);
10213 this.conn.request(o);
10216 callback.call(scope||this, null, arg, false);
10221 loadResponse : function(o, success, response){
10222 delete this.activeRequest;
10224 this.fireEvent("loadexception", this, o, response);
10225 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10230 result = o.reader.read(response);
10232 this.fireEvent("loadexception", this, o, response, e);
10233 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10237 this.fireEvent("load", this, o, o.request.arg);
10238 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10242 update : function(dataSet){
10247 updateResponse : function(dataSet){
10252 * Ext JS Library 1.1.1
10253 * Copyright(c) 2006-2007, Ext JS, LLC.
10255 * Originally Released Under LGPL - original licence link has changed is not relivant.
10258 * <script type="text/javascript">
10262 * @class Roo.data.ScriptTagProxy
10263 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10264 * other than the originating domain of the running page.<br><br>
10266 * <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
10267 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10269 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10270 * source code that is used as the source inside a <script> tag.<br><br>
10272 * In order for the browser to process the returned data, the server must wrap the data object
10273 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10274 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10275 * depending on whether the callback name was passed:
10278 boolean scriptTag = false;
10279 String cb = request.getParameter("callback");
10282 response.setContentType("text/javascript");
10284 response.setContentType("application/x-json");
10286 Writer out = response.getWriter();
10288 out.write(cb + "(");
10290 out.print(dataBlock.toJsonString());
10297 * @param {Object} config A configuration object.
10299 Roo.data.ScriptTagProxy = function(config){
10300 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10301 Roo.apply(this, config);
10302 this.head = document.getElementsByTagName("head")[0];
10305 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10307 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10309 * @cfg {String} url The URL from which to request the data object.
10312 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10316 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10317 * the server the name of the callback function set up by the load call to process the returned data object.
10318 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10319 * javascript output which calls this named function passing the data object as its only parameter.
10321 callbackParam : "callback",
10323 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10324 * name to the request.
10329 * Load data from the configured URL, read the data object into
10330 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10331 * process that block using the passed callback.
10332 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10333 * for the request to the remote server.
10334 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10335 * object into a block of Roo.data.Records.
10336 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10337 * The function must be passed <ul>
10338 * <li>The Record block object</li>
10339 * <li>The "arg" argument from the load function</li>
10340 * <li>A boolean success indicator</li>
10342 * @param {Object} scope The scope in which to call the callback
10343 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10345 load : function(params, reader, callback, scope, arg){
10346 if(this.fireEvent("beforeload", this, params) !== false){
10348 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10350 var url = this.url;
10351 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10353 url += "&_dc=" + (new Date().getTime());
10355 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10358 cb : "stcCallback"+transId,
10359 scriptId : "stcScript"+transId,
10363 callback : callback,
10369 window[trans.cb] = function(o){
10370 conn.handleResponse(o, trans);
10373 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10375 if(this.autoAbort !== false){
10379 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10381 var script = document.createElement("script");
10382 script.setAttribute("src", url);
10383 script.setAttribute("type", "text/javascript");
10384 script.setAttribute("id", trans.scriptId);
10385 this.head.appendChild(script);
10387 this.trans = trans;
10389 callback.call(scope||this, null, arg, false);
10394 isLoading : function(){
10395 return this.trans ? true : false;
10399 * Abort the current server request.
10401 abort : function(){
10402 if(this.isLoading()){
10403 this.destroyTrans(this.trans);
10408 destroyTrans : function(trans, isLoaded){
10409 this.head.removeChild(document.getElementById(trans.scriptId));
10410 clearTimeout(trans.timeoutId);
10412 window[trans.cb] = undefined;
10414 delete window[trans.cb];
10417 // if hasn't been loaded, wait for load to remove it to prevent script error
10418 window[trans.cb] = function(){
10419 window[trans.cb] = undefined;
10421 delete window[trans.cb];
10428 handleResponse : function(o, trans){
10429 this.trans = false;
10430 this.destroyTrans(trans, true);
10433 result = trans.reader.readRecords(o);
10435 this.fireEvent("loadexception", this, o, trans.arg, e);
10436 trans.callback.call(trans.scope||window, null, trans.arg, false);
10439 this.fireEvent("load", this, o, trans.arg);
10440 trans.callback.call(trans.scope||window, result, trans.arg, true);
10444 handleFailure : function(trans){
10445 this.trans = false;
10446 this.destroyTrans(trans, false);
10447 this.fireEvent("loadexception", this, null, trans.arg);
10448 trans.callback.call(trans.scope||window, null, trans.arg, false);
10452 * Ext JS Library 1.1.1
10453 * Copyright(c) 2006-2007, Ext JS, LLC.
10455 * Originally Released Under LGPL - original licence link has changed is not relivant.
10458 * <script type="text/javascript">
10462 * @class Roo.data.JsonReader
10463 * @extends Roo.data.DataReader
10464 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10465 * based on mappings in a provided Roo.data.Record constructor.
10467 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10468 * in the reply previously.
10473 var RecordDef = Roo.data.Record.create([
10474 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10475 {name: 'occupation'} // This field will use "occupation" as the mapping.
10477 var myReader = new Roo.data.JsonReader({
10478 totalProperty: "results", // The property which contains the total dataset size (optional)
10479 root: "rows", // The property which contains an Array of row objects
10480 id: "id" // The property within each row object that provides an ID for the record (optional)
10484 * This would consume a JSON file like this:
10486 { 'results': 2, 'rows': [
10487 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10488 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10491 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10492 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10493 * paged from the remote server.
10494 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10495 * @cfg {String} root name of the property which contains the Array of row objects.
10496 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10498 * Create a new JsonReader
10499 * @param {Object} meta Metadata configuration options
10500 * @param {Object} recordType Either an Array of field definition objects,
10501 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10503 Roo.data.JsonReader = function(meta, recordType){
10506 // set some defaults:
10507 Roo.applyIf(meta, {
10508 totalProperty: 'total',
10509 successProperty : 'success',
10514 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10516 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10519 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10520 * Used by Store query builder to append _requestMeta to params.
10523 metaFromRemote : false,
10525 * This method is only used by a DataProxy which has retrieved data from a remote server.
10526 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10527 * @return {Object} data A data block which is used by an Roo.data.Store object as
10528 * a cache of Roo.data.Records.
10530 read : function(response){
10531 var json = response.responseText;
10533 var o = /* eval:var:o */ eval("("+json+")");
10535 throw {message: "JsonReader.read: Json object not found"};
10541 this.metaFromRemote = true;
10542 this.meta = o.metaData;
10543 this.recordType = Roo.data.Record.create(o.metaData.fields);
10544 this.onMetaChange(this.meta, this.recordType, o);
10546 return this.readRecords(o);
10549 // private function a store will implement
10550 onMetaChange : function(meta, recordType, o){
10557 simpleAccess: function(obj, subsc) {
10564 getJsonAccessor: function(){
10566 return function(expr) {
10568 return(re.test(expr))
10569 ? new Function("obj", "return obj." + expr)
10574 return Roo.emptyFn;
10579 * Create a data block containing Roo.data.Records from an XML document.
10580 * @param {Object} o An object which contains an Array of row objects in the property specified
10581 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10582 * which contains the total size of the dataset.
10583 * @return {Object} data A data block which is used by an Roo.data.Store object as
10584 * a cache of Roo.data.Records.
10586 readRecords : function(o){
10588 * After any data loads, the raw JSON data is available for further custom processing.
10592 var s = this.meta, Record = this.recordType,
10593 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10595 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10597 if(s.totalProperty) {
10598 this.getTotal = this.getJsonAccessor(s.totalProperty);
10600 if(s.successProperty) {
10601 this.getSuccess = this.getJsonAccessor(s.successProperty);
10603 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10605 var g = this.getJsonAccessor(s.id);
10606 this.getId = function(rec) {
10608 return (r === undefined || r === "") ? null : r;
10611 this.getId = function(){return null;};
10614 for(var jj = 0; jj < fl; jj++){
10616 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10617 this.ef[jj] = this.getJsonAccessor(map);
10621 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10622 if(s.totalProperty){
10623 var vt = parseInt(this.getTotal(o), 10);
10628 if(s.successProperty){
10629 var vs = this.getSuccess(o);
10630 if(vs === false || vs === 'false'){
10635 for(var i = 0; i < c; i++){
10638 var id = this.getId(n);
10639 for(var j = 0; j < fl; j++){
10641 var v = this.ef[j](n);
10643 Roo.log('missing convert for ' + f.name);
10647 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10649 var record = new Record(values, id);
10651 records[i] = record;
10657 totalRecords : totalRecords
10662 * Ext JS Library 1.1.1
10663 * Copyright(c) 2006-2007, Ext JS, LLC.
10665 * Originally Released Under LGPL - original licence link has changed is not relivant.
10668 * <script type="text/javascript">
10672 * @class Roo.data.ArrayReader
10673 * @extends Roo.data.DataReader
10674 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10675 * Each element of that Array represents a row of data fields. The
10676 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10677 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10681 var RecordDef = Roo.data.Record.create([
10682 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10683 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10685 var myReader = new Roo.data.ArrayReader({
10686 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10690 * This would consume an Array like this:
10692 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10694 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10696 * Create a new JsonReader
10697 * @param {Object} meta Metadata configuration options.
10698 * @param {Object} recordType Either an Array of field definition objects
10699 * as specified to {@link Roo.data.Record#create},
10700 * or an {@link Roo.data.Record} object
10701 * created using {@link Roo.data.Record#create}.
10703 Roo.data.ArrayReader = function(meta, recordType){
10704 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10707 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10709 * Create a data block containing Roo.data.Records from an XML document.
10710 * @param {Object} o An Array of row objects which represents the dataset.
10711 * @return {Object} data A data block which is used by an Roo.data.Store object as
10712 * a cache of Roo.data.Records.
10714 readRecords : function(o){
10715 var sid = this.meta ? this.meta.id : null;
10716 var recordType = this.recordType, fields = recordType.prototype.fields;
10719 for(var i = 0; i < root.length; i++){
10722 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10723 for(var j = 0, jlen = fields.length; j < jlen; j++){
10724 var f = fields.items[j];
10725 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10726 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10728 values[f.name] = v;
10730 var record = new recordType(values, id);
10732 records[records.length] = record;
10736 totalRecords : records.length
10745 * @class Roo.bootstrap.ComboBox
10746 * @extends Roo.bootstrap.TriggerField
10747 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10748 * @cfg {Boolean} append (true|false) default false
10749 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10750 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10751 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10752 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10753 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10755 * Create a new ComboBox.
10756 * @param {Object} config Configuration options
10758 Roo.bootstrap.ComboBox = function(config){
10759 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10763 * Fires when the dropdown list is expanded
10764 * @param {Roo.bootstrap.ComboBox} combo This combo box
10769 * Fires when the dropdown list is collapsed
10770 * @param {Roo.bootstrap.ComboBox} combo This combo box
10774 * @event beforeselect
10775 * Fires before a list item is selected. Return false to cancel the selection.
10776 * @param {Roo.bootstrap.ComboBox} combo This combo box
10777 * @param {Roo.data.Record} record The data record returned from the underlying store
10778 * @param {Number} index The index of the selected item in the dropdown list
10780 'beforeselect' : true,
10783 * Fires when a list item is selected
10784 * @param {Roo.bootstrap.ComboBox} combo This combo box
10785 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10786 * @param {Number} index The index of the selected item in the dropdown list
10790 * @event beforequery
10791 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10792 * The event object passed has these properties:
10793 * @param {Roo.bootstrap.ComboBox} combo This combo box
10794 * @param {String} query The query
10795 * @param {Boolean} forceAll true to force "all" query
10796 * @param {Boolean} cancel true to cancel the query
10797 * @param {Object} e The query event object
10799 'beforequery': true,
10802 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10803 * @param {Roo.bootstrap.ComboBox} combo This combo box
10808 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10809 * @param {Roo.bootstrap.ComboBox} combo This combo box
10810 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10815 * Fires when the remove value from the combobox array
10816 * @param {Roo.bootstrap.ComboBox} combo This combo box
10820 * @event specialfilter
10821 * Fires when specialfilter
10822 * @param {Roo.bootstrap.ComboBox} combo This combo box
10824 'specialfilter' : true
10829 this.tickItems = [];
10831 this.selectedIndex = -1;
10832 if(this.mode == 'local'){
10833 if(config.queryDelay === undefined){
10834 this.queryDelay = 10;
10836 if(config.minChars === undefined){
10842 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10845 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10846 * rendering into an Roo.Editor, defaults to false)
10849 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10850 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10853 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10856 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10857 * the dropdown list (defaults to undefined, with no header element)
10861 * @cfg {String/Roo.Template} tpl The template to use to render the output
10865 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10867 listWidth: undefined,
10869 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10870 * mode = 'remote' or 'text' if mode = 'local')
10872 displayField: undefined,
10875 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10876 * mode = 'remote' or 'value' if mode = 'local').
10877 * Note: use of a valueField requires the user make a selection
10878 * in order for a value to be mapped.
10880 valueField: undefined,
10884 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10885 * field's data value (defaults to the underlying DOM element's name)
10887 hiddenName: undefined,
10889 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10893 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10895 selectedClass: 'active',
10898 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10902 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10903 * anchor positions (defaults to 'tl-bl')
10905 listAlign: 'tl-bl?',
10907 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10911 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10912 * query specified by the allQuery config option (defaults to 'query')
10914 triggerAction: 'query',
10916 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10917 * (defaults to 4, does not apply if editable = false)
10921 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10922 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10926 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10927 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10931 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10932 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10936 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10937 * when editable = true (defaults to false)
10939 selectOnFocus:false,
10941 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10943 queryParam: 'query',
10945 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10946 * when mode = 'remote' (defaults to 'Loading...')
10948 loadingText: 'Loading...',
10950 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10954 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10958 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10959 * traditional select (defaults to true)
10963 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10967 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10971 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10972 * listWidth has a higher value)
10976 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10977 * allow the user to set arbitrary text into the field (defaults to false)
10979 forceSelection:false,
10981 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10982 * if typeAhead = true (defaults to 250)
10984 typeAheadDelay : 250,
10986 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10987 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10989 valueNotFoundText : undefined,
10991 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10993 blockFocus : false,
10996 * @cfg {Boolean} disableClear Disable showing of clear button.
10998 disableClear : false,
11000 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11002 alwaysQuery : false,
11005 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11010 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11012 invalidClass : "has-warning",
11015 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11017 validClass : "has-success",
11020 * @cfg {Boolean} specialFilter (true|false) special filter default false
11022 specialFilter : false,
11034 btnPosition : 'right',
11035 triggerList : true,
11036 showToggleBtn : true,
11037 // element that contains real text value.. (when hidden is used..)
11039 getAutoCreate : function()
11046 if(!this.tickable){
11047 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11052 * ComboBox with tickable selections
11055 var align = this.labelAlign || this.parentLabelAlign();
11058 cls : 'form-group roo-combobox-tickable' //input-group
11063 cls : 'tickable-buttons',
11068 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11075 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11082 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11089 buttons.cn.unshift({
11091 cls: 'select2-search-field-input'
11097 Roo.each(buttons.cn, function(c){
11099 c.cls += ' btn-' + _this.size;
11102 if (_this.disabled) {
11113 cls: 'form-hidden-field'
11117 cls: 'select2-choices',
11121 cls: 'select2-search-field',
11133 cls: 'select2-container input-group select2-container-multi',
11138 // cls: 'typeahead typeahead-long dropdown-menu',
11139 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11144 if(this.hasFeedback && !this.allowBlank){
11148 cls: 'glyphicon form-control-feedback'
11151 combobox.cn.push(feedback);
11154 if (align ==='left' && this.fieldLabel.length) {
11156 Roo.log("left and has label");
11162 cls : 'control-label col-sm-' + this.labelWidth,
11163 html : this.fieldLabel
11167 cls : "col-sm-" + (12 - this.labelWidth),
11174 } else if ( this.fieldLabel.length) {
11180 //cls : 'input-group-addon',
11181 html : this.fieldLabel
11191 Roo.log(" no label && no align");
11198 ['xs','sm','md','lg'].map(function(size){
11199 if (settings[size]) {
11200 cfg.cls += ' col-' + size + '-' + settings[size];
11209 initEvents: function()
11213 throw "can not find store for combo";
11215 this.store = Roo.factory(this.store, Roo.data);
11218 this.initTickableEvents();
11222 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11224 if(this.hiddenName){
11226 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11228 this.hiddenField.dom.value =
11229 this.hiddenValue !== undefined ? this.hiddenValue :
11230 this.value !== undefined ? this.value : '';
11232 // prevent input submission
11233 this.el.dom.removeAttribute('name');
11234 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11239 // this.el.dom.setAttribute('autocomplete', 'off');
11242 var cls = 'x-combo-list';
11244 //this.list = new Roo.Layer({
11245 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11251 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11252 _this.list.setWidth(lw);
11255 this.list.on('mouseover', this.onViewOver, this);
11256 this.list.on('mousemove', this.onViewMove, this);
11258 this.list.on('scroll', this.onViewScroll, this);
11261 this.list.swallowEvent('mousewheel');
11262 this.assetHeight = 0;
11265 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11266 this.assetHeight += this.header.getHeight();
11269 this.innerList = this.list.createChild({cls:cls+'-inner'});
11270 this.innerList.on('mouseover', this.onViewOver, this);
11271 this.innerList.on('mousemove', this.onViewMove, this);
11272 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11274 if(this.allowBlank && !this.pageSize && !this.disableClear){
11275 this.footer = this.list.createChild({cls:cls+'-ft'});
11276 this.pageTb = new Roo.Toolbar(this.footer);
11280 this.footer = this.list.createChild({cls:cls+'-ft'});
11281 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11282 {pageSize: this.pageSize});
11286 if (this.pageTb && this.allowBlank && !this.disableClear) {
11288 this.pageTb.add(new Roo.Toolbar.Fill(), {
11289 cls: 'x-btn-icon x-btn-clear',
11291 handler: function()
11294 _this.clearValue();
11295 _this.onSelect(false, -1);
11300 this.assetHeight += this.footer.getHeight();
11305 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11308 this.view = new Roo.View(this.list, this.tpl, {
11309 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11311 //this.view.wrapEl.setDisplayed(false);
11312 this.view.on('click', this.onViewClick, this);
11316 this.store.on('beforeload', this.onBeforeLoad, this);
11317 this.store.on('load', this.onLoad, this);
11318 this.store.on('loadexception', this.onLoadException, this);
11320 if(this.resizable){
11321 this.resizer = new Roo.Resizable(this.list, {
11322 pinned:true, handles:'se'
11324 this.resizer.on('resize', function(r, w, h){
11325 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11326 this.listWidth = w;
11327 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11328 this.restrictHeight();
11330 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11333 if(!this.editable){
11334 this.editable = true;
11335 this.setEditable(false);
11340 if (typeof(this.events.add.listeners) != 'undefined') {
11342 this.addicon = this.wrap.createChild(
11343 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11345 this.addicon.on('click', function(e) {
11346 this.fireEvent('add', this);
11349 if (typeof(this.events.edit.listeners) != 'undefined') {
11351 this.editicon = this.wrap.createChild(
11352 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11353 if (this.addicon) {
11354 this.editicon.setStyle('margin-left', '40px');
11356 this.editicon.on('click', function(e) {
11358 // we fire even if inothing is selected..
11359 this.fireEvent('edit', this, this.lastData );
11365 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11366 "up" : function(e){
11367 this.inKeyMode = true;
11371 "down" : function(e){
11372 if(!this.isExpanded()){
11373 this.onTriggerClick();
11375 this.inKeyMode = true;
11380 "enter" : function(e){
11381 // this.onViewClick();
11385 if(this.fireEvent("specialkey", this, e)){
11386 this.onViewClick(false);
11392 "esc" : function(e){
11396 "tab" : function(e){
11399 if(this.fireEvent("specialkey", this, e)){
11400 this.onViewClick(false);
11408 doRelay : function(foo, bar, hname){
11409 if(hname == 'down' || this.scope.isExpanded()){
11410 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11419 this.queryDelay = Math.max(this.queryDelay || 10,
11420 this.mode == 'local' ? 10 : 250);
11423 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11425 if(this.typeAhead){
11426 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11428 if(this.editable !== false){
11429 this.inputEl().on("keyup", this.onKeyUp, this);
11431 if(this.forceSelection){
11432 this.inputEl().on('blur', this.doForce, this);
11436 this.choices = this.el.select('ul.select2-choices', true).first();
11437 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11441 initTickableEvents: function()
11445 if(this.hiddenName){
11447 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11449 this.hiddenField.dom.value =
11450 this.hiddenValue !== undefined ? this.hiddenValue :
11451 this.value !== undefined ? this.value : '';
11453 // prevent input submission
11454 this.el.dom.removeAttribute('name');
11455 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11460 // this.list = this.el.select('ul.dropdown-menu',true).first();
11462 this.choices = this.el.select('ul.select2-choices', true).first();
11463 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11464 if(this.triggerList){
11465 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11468 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11469 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11471 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11472 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11474 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11475 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11477 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11478 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11479 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11482 this.cancelBtn.hide();
11487 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11488 _this.list.setWidth(lw);
11491 this.list.on('mouseover', this.onViewOver, this);
11492 this.list.on('mousemove', this.onViewMove, this);
11494 this.list.on('scroll', this.onViewScroll, this);
11497 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11500 this.view = new Roo.View(this.list, this.tpl, {
11501 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11504 //this.view.wrapEl.setDisplayed(false);
11505 this.view.on('click', this.onViewClick, this);
11509 this.store.on('beforeload', this.onBeforeLoad, this);
11510 this.store.on('load', this.onLoad, this);
11511 this.store.on('loadexception', this.onLoadException, this);
11514 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11515 "up" : function(e){
11516 this.inKeyMode = true;
11520 "down" : function(e){
11521 this.inKeyMode = true;
11525 "enter" : function(e){
11526 if(this.fireEvent("specialkey", this, e)){
11527 this.onViewClick(false);
11533 "esc" : function(e){
11534 this.onTickableFooterButtonClick(e, false, false);
11537 "tab" : function(e){
11538 this.fireEvent("specialkey", this, e);
11540 this.onTickableFooterButtonClick(e, false, false);
11547 doRelay : function(e, fn, key){
11548 if(this.scope.isExpanded()){
11549 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11558 this.queryDelay = Math.max(this.queryDelay || 10,
11559 this.mode == 'local' ? 10 : 250);
11562 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11564 if(this.typeAhead){
11565 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11568 if(this.editable !== false){
11569 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11574 onDestroy : function(){
11576 this.view.setStore(null);
11577 this.view.el.removeAllListeners();
11578 this.view.el.remove();
11579 this.view.purgeListeners();
11582 this.list.dom.innerHTML = '';
11586 this.store.un('beforeload', this.onBeforeLoad, this);
11587 this.store.un('load', this.onLoad, this);
11588 this.store.un('loadexception', this.onLoadException, this);
11590 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11594 fireKey : function(e){
11595 if(e.isNavKeyPress() && !this.list.isVisible()){
11596 this.fireEvent("specialkey", this, e);
11601 onResize: function(w, h){
11602 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11604 // if(typeof w != 'number'){
11605 // // we do not handle it!?!?
11608 // var tw = this.trigger.getWidth();
11609 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11610 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11612 // this.inputEl().setWidth( this.adjustWidth('input', x));
11614 // //this.trigger.setStyle('left', x+'px');
11616 // if(this.list && this.listWidth === undefined){
11617 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11618 // this.list.setWidth(lw);
11619 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11627 * Allow or prevent the user from directly editing the field text. If false is passed,
11628 * the user will only be able to select from the items defined in the dropdown list. This method
11629 * is the runtime equivalent of setting the 'editable' config option at config time.
11630 * @param {Boolean} value True to allow the user to directly edit the field text
11632 setEditable : function(value){
11633 if(value == this.editable){
11636 this.editable = value;
11638 this.inputEl().dom.setAttribute('readOnly', true);
11639 this.inputEl().on('mousedown', this.onTriggerClick, this);
11640 this.inputEl().addClass('x-combo-noedit');
11642 this.inputEl().dom.setAttribute('readOnly', false);
11643 this.inputEl().un('mousedown', this.onTriggerClick, this);
11644 this.inputEl().removeClass('x-combo-noedit');
11650 onBeforeLoad : function(combo,opts){
11651 if(!this.hasFocus){
11655 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11657 this.restrictHeight();
11658 this.selectedIndex = -1;
11662 onLoad : function(){
11664 this.hasQuery = false;
11666 if(!this.hasFocus){
11670 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11671 this.loading.hide();
11674 if(this.store.getCount() > 0){
11676 this.restrictHeight();
11677 if(this.lastQuery == this.allQuery){
11678 if(this.editable && !this.tickable){
11679 this.inputEl().dom.select();
11683 !this.selectByValue(this.value, true) &&
11686 !this.store.lastOptions ||
11687 typeof(this.store.lastOptions.add) == 'undefined' ||
11688 this.store.lastOptions.add != true
11691 this.select(0, true);
11694 if(this.autoFocus){
11697 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11698 this.taTask.delay(this.typeAheadDelay);
11702 this.onEmptyResults();
11708 onLoadException : function()
11710 this.hasQuery = false;
11712 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11713 this.loading.hide();
11716 if(this.tickable && this.editable){
11722 Roo.log(this.store.reader.jsonData);
11723 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11725 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11731 onTypeAhead : function(){
11732 if(this.store.getCount() > 0){
11733 var r = this.store.getAt(0);
11734 var newValue = r.data[this.displayField];
11735 var len = newValue.length;
11736 var selStart = this.getRawValue().length;
11738 if(selStart != len){
11739 this.setRawValue(newValue);
11740 this.selectText(selStart, newValue.length);
11746 onSelect : function(record, index){
11748 if(this.fireEvent('beforeselect', this, record, index) !== false){
11750 this.setFromData(index > -1 ? record.data : false);
11753 this.fireEvent('select', this, record, index);
11758 * Returns the currently selected field value or empty string if no value is set.
11759 * @return {String} value The selected value
11761 getValue : function(){
11764 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11767 if(this.valueField){
11768 return typeof this.value != 'undefined' ? this.value : '';
11770 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11775 * Clears any text/value currently set in the field
11777 clearValue : function(){
11778 if(this.hiddenField){
11779 this.hiddenField.dom.value = '';
11782 this.setRawValue('');
11783 this.lastSelectionText = '';
11784 this.lastData = false;
11789 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11790 * will be displayed in the field. If the value does not match the data value of an existing item,
11791 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11792 * Otherwise the field will be blank (although the value will still be set).
11793 * @param {String} value The value to match
11795 setValue : function(v){
11802 if(this.valueField){
11803 var r = this.findRecord(this.valueField, v);
11805 text = r.data[this.displayField];
11806 }else if(this.valueNotFoundText !== undefined){
11807 text = this.valueNotFoundText;
11810 this.lastSelectionText = text;
11811 if(this.hiddenField){
11812 this.hiddenField.dom.value = v;
11814 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11818 * @property {Object} the last set data for the element
11823 * Sets the value of the field based on a object which is related to the record format for the store.
11824 * @param {Object} value the value to set as. or false on reset?
11826 setFromData : function(o){
11833 var dv = ''; // display value
11834 var vv = ''; // value value..
11836 if (this.displayField) {
11837 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11839 // this is an error condition!!!
11840 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11843 if(this.valueField){
11844 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11847 if(this.hiddenField){
11848 this.hiddenField.dom.value = vv;
11850 this.lastSelectionText = dv;
11851 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11855 // no hidden field.. - we store the value in 'value', but still display
11856 // display field!!!!
11857 this.lastSelectionText = dv;
11858 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11864 reset : function(){
11865 // overridden so that last data is reset..
11872 this.setValue(this.originalValue);
11873 this.clearInvalid();
11874 this.lastData = false;
11876 this.view.clearSelections();
11880 findRecord : function(prop, value){
11882 if(this.store.getCount() > 0){
11883 this.store.each(function(r){
11884 if(r.data[prop] == value){
11894 getName: function()
11896 // returns hidden if it's set..
11897 if (!this.rendered) {return ''};
11898 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11902 onViewMove : function(e, t){
11903 this.inKeyMode = false;
11907 onViewOver : function(e, t){
11908 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11911 var item = this.view.findItemFromChild(t);
11914 var index = this.view.indexOf(item);
11915 this.select(index, false);
11920 onViewClick : function(view, doFocus, el, e)
11922 var index = this.view.getSelectedIndexes()[0];
11924 var r = this.store.getAt(index);
11928 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11935 Roo.each(this.tickItems, function(v,k){
11937 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11938 _this.tickItems.splice(k, 1);
11940 if(typeof(e) == 'undefined' && view == false){
11941 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11953 this.tickItems.push(r.data);
11955 if(typeof(e) == 'undefined' && view == false){
11956 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11963 this.onSelect(r, index);
11965 if(doFocus !== false && !this.blockFocus){
11966 this.inputEl().focus();
11971 restrictHeight : function(){
11972 //this.innerList.dom.style.height = '';
11973 //var inner = this.innerList.dom;
11974 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11975 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11976 //this.list.beginUpdate();
11977 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11978 this.list.alignTo(this.inputEl(), this.listAlign);
11979 this.list.alignTo(this.inputEl(), this.listAlign);
11980 //this.list.endUpdate();
11984 onEmptyResults : function(){
11986 if(this.tickable && this.editable){
11987 this.restrictHeight();
11995 * Returns true if the dropdown list is expanded, else false.
11997 isExpanded : function(){
11998 return this.list.isVisible();
12002 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12003 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12004 * @param {String} value The data value of the item to select
12005 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12006 * selected item if it is not currently in view (defaults to true)
12007 * @return {Boolean} True if the value matched an item in the list, else false
12009 selectByValue : function(v, scrollIntoView){
12010 if(v !== undefined && v !== null){
12011 var r = this.findRecord(this.valueField || this.displayField, v);
12013 this.select(this.store.indexOf(r), scrollIntoView);
12021 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12022 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12023 * @param {Number} index The zero-based index of the list item to select
12024 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12025 * selected item if it is not currently in view (defaults to true)
12027 select : function(index, scrollIntoView){
12028 this.selectedIndex = index;
12029 this.view.select(index);
12030 if(scrollIntoView !== false){
12031 var el = this.view.getNode(index);
12033 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12036 this.list.scrollChildIntoView(el, false);
12042 selectNext : function(){
12043 var ct = this.store.getCount();
12045 if(this.selectedIndex == -1){
12047 }else if(this.selectedIndex < ct-1){
12048 this.select(this.selectedIndex+1);
12054 selectPrev : function(){
12055 var ct = this.store.getCount();
12057 if(this.selectedIndex == -1){
12059 }else if(this.selectedIndex != 0){
12060 this.select(this.selectedIndex-1);
12066 onKeyUp : function(e){
12067 if(this.editable !== false && !e.isSpecialKey()){
12068 this.lastKey = e.getKey();
12069 this.dqTask.delay(this.queryDelay);
12074 validateBlur : function(){
12075 return !this.list || !this.list.isVisible();
12079 initQuery : function(){
12081 var v = this.getRawValue();
12083 if(this.tickable && this.editable){
12084 v = this.tickableInputEl().getValue();
12091 doForce : function(){
12092 if(this.inputEl().dom.value.length > 0){
12093 this.inputEl().dom.value =
12094 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12100 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12101 * query allowing the query action to be canceled if needed.
12102 * @param {String} query The SQL query to execute
12103 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12104 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12105 * saved in the current store (defaults to false)
12107 doQuery : function(q, forceAll){
12109 if(q === undefined || q === null){
12114 forceAll: forceAll,
12118 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12123 forceAll = qe.forceAll;
12124 if(forceAll === true || (q.length >= this.minChars)){
12126 this.hasQuery = true;
12128 if(this.lastQuery != q || this.alwaysQuery){
12129 this.lastQuery = q;
12130 if(this.mode == 'local'){
12131 this.selectedIndex = -1;
12133 this.store.clearFilter();
12136 if(this.specialFilter){
12137 this.fireEvent('specialfilter', this);
12142 this.store.filter(this.displayField, q);
12145 this.store.fireEvent("datachanged", this.store);
12152 this.store.baseParams[this.queryParam] = q;
12154 var options = {params : this.getParams(q)};
12157 options.add = true;
12158 options.params.start = this.page * this.pageSize;
12161 this.store.load(options);
12164 * this code will make the page width larger, at the beginning, the list not align correctly,
12165 * we should expand the list on onLoad
12166 * so command out it
12171 this.selectedIndex = -1;
12176 this.loadNext = false;
12180 getParams : function(q){
12182 //p[this.queryParam] = q;
12186 p.limit = this.pageSize;
12192 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12194 collapse : function(){
12195 if(!this.isExpanded()){
12202 this.hasFocus = false;
12204 this.cancelBtn.hide();
12205 this.trigger.show();
12208 this.tickableInputEl().dom.value = '';
12209 this.tickableInputEl().blur();
12214 Roo.get(document).un('mousedown', this.collapseIf, this);
12215 Roo.get(document).un('mousewheel', this.collapseIf, this);
12216 if (!this.editable) {
12217 Roo.get(document).un('keydown', this.listKeyPress, this);
12219 this.fireEvent('collapse', this);
12223 collapseIf : function(e){
12224 var in_combo = e.within(this.el);
12225 var in_list = e.within(this.list);
12226 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12228 if (in_combo || in_list || is_list) {
12229 //e.stopPropagation();
12234 this.onTickableFooterButtonClick(e, false, false);
12242 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12244 expand : function(){
12246 if(this.isExpanded() || !this.hasFocus){
12250 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12251 this.list.setWidth(lw);
12258 this.restrictHeight();
12262 this.tickItems = Roo.apply([], this.item);
12265 this.cancelBtn.show();
12266 this.trigger.hide();
12269 this.tickableInputEl().focus();
12274 Roo.get(document).on('mousedown', this.collapseIf, this);
12275 Roo.get(document).on('mousewheel', this.collapseIf, this);
12276 if (!this.editable) {
12277 Roo.get(document).on('keydown', this.listKeyPress, this);
12280 this.fireEvent('expand', this);
12284 // Implements the default empty TriggerField.onTriggerClick function
12285 onTriggerClick : function(e)
12287 Roo.log('trigger click');
12289 if(this.disabled || !this.triggerList){
12294 this.loadNext = false;
12296 if(this.isExpanded()){
12298 if (!this.blockFocus) {
12299 this.inputEl().focus();
12303 this.hasFocus = true;
12304 if(this.triggerAction == 'all') {
12305 this.doQuery(this.allQuery, true);
12307 this.doQuery(this.getRawValue());
12309 if (!this.blockFocus) {
12310 this.inputEl().focus();
12315 onTickableTriggerClick : function(e)
12322 this.loadNext = false;
12323 this.hasFocus = true;
12325 if(this.triggerAction == 'all') {
12326 this.doQuery(this.allQuery, true);
12328 this.doQuery(this.getRawValue());
12332 onSearchFieldClick : function(e)
12334 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12335 this.onTickableFooterButtonClick(e, false, false);
12339 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12344 this.loadNext = false;
12345 this.hasFocus = true;
12347 if(this.triggerAction == 'all') {
12348 this.doQuery(this.allQuery, true);
12350 this.doQuery(this.getRawValue());
12354 listKeyPress : function(e)
12356 //Roo.log('listkeypress');
12357 // scroll to first matching element based on key pres..
12358 if (e.isSpecialKey()) {
12361 var k = String.fromCharCode(e.getKey()).toUpperCase();
12364 var csel = this.view.getSelectedNodes();
12365 var cselitem = false;
12367 var ix = this.view.indexOf(csel[0]);
12368 cselitem = this.store.getAt(ix);
12369 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12375 this.store.each(function(v) {
12377 // start at existing selection.
12378 if (cselitem.id == v.id) {
12384 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12385 match = this.store.indexOf(v);
12391 if (match === false) {
12392 return true; // no more action?
12395 this.view.select(match);
12396 var sn = Roo.get(this.view.getSelectedNodes()[0])
12397 sn.scrollIntoView(sn.dom.parentNode, false);
12400 onViewScroll : function(e, t){
12402 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
12406 this.hasQuery = true;
12408 this.loading = this.list.select('.loading', true).first();
12410 if(this.loading === null){
12411 this.list.createChild({
12413 cls: 'loading select2-more-results select2-active',
12414 html: 'Loading more results...'
12417 this.loading = this.list.select('.loading', true).first();
12419 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12421 this.loading.hide();
12424 this.loading.show();
12429 this.loadNext = true;
12431 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12436 addItem : function(o)
12438 var dv = ''; // display value
12440 if (this.displayField) {
12441 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12443 // this is an error condition!!!
12444 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12451 var choice = this.choices.createChild({
12453 cls: 'select2-search-choice',
12462 cls: 'select2-search-choice-close',
12467 }, this.searchField);
12469 var close = choice.select('a.select2-search-choice-close', true).first()
12471 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12479 this.inputEl().dom.value = '';
12484 onRemoveItem : function(e, _self, o)
12486 e.preventDefault();
12488 this.lastItem = Roo.apply([], this.item);
12490 var index = this.item.indexOf(o.data) * 1;
12493 Roo.log('not this item?!');
12497 this.item.splice(index, 1);
12502 this.fireEvent('remove', this, e);
12508 syncValue : function()
12510 if(!this.item.length){
12517 Roo.each(this.item, function(i){
12518 if(_this.valueField){
12519 value.push(i[_this.valueField]);
12526 this.value = value.join(',');
12528 if(this.hiddenField){
12529 this.hiddenField.dom.value = this.value;
12532 this.store.fireEvent("datachanged", this.store);
12535 clearItem : function()
12537 if(!this.multiple){
12543 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12552 inputEl: function ()
12555 return this.searchField;
12557 return this.el.select('input.form-control',true).first();
12561 onTickableFooterButtonClick : function(e, btn, el)
12563 e.preventDefault();
12565 this.lastItem = Roo.apply([], this.item);
12567 if(btn && btn.name == 'cancel'){
12568 this.tickItems = Roo.apply([], this.item);
12577 Roo.each(this.tickItems, function(o){
12585 validate : function()
12587 var v = this.getRawValue();
12590 v = this.getValue();
12593 if(this.disabled || this.allowBlank || v.length){
12598 this.markInvalid();
12602 tickableInputEl : function()
12604 if(!this.tickable || !this.editable){
12605 return this.inputEl();
12608 return this.inputEl().select('.select2-search-field-input', true).first();
12614 * @cfg {Boolean} grow
12618 * @cfg {Number} growMin
12622 * @cfg {Number} growMax
12632 * Ext JS Library 1.1.1
12633 * Copyright(c) 2006-2007, Ext JS, LLC.
12635 * Originally Released Under LGPL - original licence link has changed is not relivant.
12638 * <script type="text/javascript">
12643 * @extends Roo.util.Observable
12644 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12645 * This class also supports single and multi selection modes. <br>
12646 * Create a data model bound view:
12648 var store = new Roo.data.Store(...);
12650 var view = new Roo.View({
12652 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12654 singleSelect: true,
12655 selectedClass: "ydataview-selected",
12659 // listen for node click?
12660 view.on("click", function(vw, index, node, e){
12661 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12665 dataModel.load("foobar.xml");
12667 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12669 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12670 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12672 * Note: old style constructor is still suported (container, template, config)
12675 * Create a new View
12676 * @param {Object} config The config object
12679 Roo.View = function(config, depreciated_tpl, depreciated_config){
12681 this.parent = false;
12683 if (typeof(depreciated_tpl) == 'undefined') {
12684 // new way.. - universal constructor.
12685 Roo.apply(this, config);
12686 this.el = Roo.get(this.el);
12689 this.el = Roo.get(config);
12690 this.tpl = depreciated_tpl;
12691 Roo.apply(this, depreciated_config);
12693 this.wrapEl = this.el.wrap().wrap();
12694 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12697 if(typeof(this.tpl) == "string"){
12698 this.tpl = new Roo.Template(this.tpl);
12700 // support xtype ctors..
12701 this.tpl = new Roo.factory(this.tpl, Roo);
12705 this.tpl.compile();
12710 * @event beforeclick
12711 * Fires before a click is processed. Returns false to cancel the default action.
12712 * @param {Roo.View} this
12713 * @param {Number} index The index of the target node
12714 * @param {HTMLElement} node The target node
12715 * @param {Roo.EventObject} e The raw event object
12717 "beforeclick" : true,
12720 * Fires when a template node is clicked.
12721 * @param {Roo.View} this
12722 * @param {Number} index The index of the target node
12723 * @param {HTMLElement} node The target node
12724 * @param {Roo.EventObject} e The raw event object
12729 * Fires when a template node is double clicked.
12730 * @param {Roo.View} this
12731 * @param {Number} index The index of the target node
12732 * @param {HTMLElement} node The target node
12733 * @param {Roo.EventObject} e The raw event object
12737 * @event contextmenu
12738 * Fires when a template node is right clicked.
12739 * @param {Roo.View} this
12740 * @param {Number} index The index of the target node
12741 * @param {HTMLElement} node The target node
12742 * @param {Roo.EventObject} e The raw event object
12744 "contextmenu" : true,
12746 * @event selectionchange
12747 * Fires when the selected nodes change.
12748 * @param {Roo.View} this
12749 * @param {Array} selections Array of the selected nodes
12751 "selectionchange" : true,
12754 * @event beforeselect
12755 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12756 * @param {Roo.View} this
12757 * @param {HTMLElement} node The node to be selected
12758 * @param {Array} selections Array of currently selected nodes
12760 "beforeselect" : true,
12762 * @event preparedata
12763 * Fires on every row to render, to allow you to change the data.
12764 * @param {Roo.View} this
12765 * @param {Object} data to be rendered (change this)
12767 "preparedata" : true
12775 "click": this.onClick,
12776 "dblclick": this.onDblClick,
12777 "contextmenu": this.onContextMenu,
12781 this.selections = [];
12783 this.cmp = new Roo.CompositeElementLite([]);
12785 this.store = Roo.factory(this.store, Roo.data);
12786 this.setStore(this.store, true);
12789 if ( this.footer && this.footer.xtype) {
12791 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12793 this.footer.dataSource = this.store
12794 this.footer.container = fctr;
12795 this.footer = Roo.factory(this.footer, Roo);
12796 fctr.insertFirst(this.el);
12798 // this is a bit insane - as the paging toolbar seems to detach the el..
12799 // dom.parentNode.parentNode.parentNode
12800 // they get detached?
12804 Roo.View.superclass.constructor.call(this);
12809 Roo.extend(Roo.View, Roo.util.Observable, {
12812 * @cfg {Roo.data.Store} store Data store to load data from.
12817 * @cfg {String|Roo.Element} el The container element.
12822 * @cfg {String|Roo.Template} tpl The template used by this View
12826 * @cfg {String} dataName the named area of the template to use as the data area
12827 * Works with domtemplates roo-name="name"
12831 * @cfg {String} selectedClass The css class to add to selected nodes
12833 selectedClass : "x-view-selected",
12835 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12840 * @cfg {String} text to display on mask (default Loading)
12844 * @cfg {Boolean} multiSelect Allow multiple selection
12846 multiSelect : false,
12848 * @cfg {Boolean} singleSelect Allow single selection
12850 singleSelect: false,
12853 * @cfg {Boolean} toggleSelect - selecting
12855 toggleSelect : false,
12858 * @cfg {Boolean} tickable - selecting
12863 * Returns the element this view is bound to.
12864 * @return {Roo.Element}
12866 getEl : function(){
12867 return this.wrapEl;
12873 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12875 refresh : function(){
12876 //Roo.log('refresh');
12879 // if we are using something like 'domtemplate', then
12880 // the what gets used is:
12881 // t.applySubtemplate(NAME, data, wrapping data..)
12882 // the outer template then get' applied with
12883 // the store 'extra data'
12884 // and the body get's added to the
12885 // roo-name="data" node?
12886 // <span class='roo-tpl-{name}'></span> ?????
12890 this.clearSelections();
12891 this.el.update("");
12893 var records = this.store.getRange();
12894 if(records.length < 1) {
12896 // is this valid?? = should it render a template??
12898 this.el.update(this.emptyText);
12902 if (this.dataName) {
12903 this.el.update(t.apply(this.store.meta)); //????
12904 el = this.el.child('.roo-tpl-' + this.dataName);
12907 for(var i = 0, len = records.length; i < len; i++){
12908 var data = this.prepareData(records[i].data, i, records[i]);
12909 this.fireEvent("preparedata", this, data, i, records[i]);
12911 var d = Roo.apply({}, data);
12914 Roo.apply(d, {'roo-id' : Roo.id()});
12918 Roo.each(this.parent.item, function(item){
12919 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12922 Roo.apply(d, {'roo-data-checked' : 'checked'});
12926 html[html.length] = Roo.util.Format.trim(
12928 t.applySubtemplate(this.dataName, d, this.store.meta) :
12935 el.update(html.join(""));
12936 this.nodes = el.dom.childNodes;
12937 this.updateIndexes(0);
12942 * Function to override to reformat the data that is sent to
12943 * the template for each node.
12944 * DEPRICATED - use the preparedata event handler.
12945 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12946 * a JSON object for an UpdateManager bound view).
12948 prepareData : function(data, index, record)
12950 this.fireEvent("preparedata", this, data, index, record);
12954 onUpdate : function(ds, record){
12955 // Roo.log('on update');
12956 this.clearSelections();
12957 var index = this.store.indexOf(record);
12958 var n = this.nodes[index];
12959 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12960 n.parentNode.removeChild(n);
12961 this.updateIndexes(index, index);
12967 onAdd : function(ds, records, index)
12969 //Roo.log(['on Add', ds, records, index] );
12970 this.clearSelections();
12971 if(this.nodes.length == 0){
12975 var n = this.nodes[index];
12976 for(var i = 0, len = records.length; i < len; i++){
12977 var d = this.prepareData(records[i].data, i, records[i]);
12979 this.tpl.insertBefore(n, d);
12982 this.tpl.append(this.el, d);
12985 this.updateIndexes(index);
12988 onRemove : function(ds, record, index){
12989 // Roo.log('onRemove');
12990 this.clearSelections();
12991 var el = this.dataName ?
12992 this.el.child('.roo-tpl-' + this.dataName) :
12995 el.dom.removeChild(this.nodes[index]);
12996 this.updateIndexes(index);
13000 * Refresh an individual node.
13001 * @param {Number} index
13003 refreshNode : function(index){
13004 this.onUpdate(this.store, this.store.getAt(index));
13007 updateIndexes : function(startIndex, endIndex){
13008 var ns = this.nodes;
13009 startIndex = startIndex || 0;
13010 endIndex = endIndex || ns.length - 1;
13011 for(var i = startIndex; i <= endIndex; i++){
13012 ns[i].nodeIndex = i;
13017 * Changes the data store this view uses and refresh the view.
13018 * @param {Store} store
13020 setStore : function(store, initial){
13021 if(!initial && this.store){
13022 this.store.un("datachanged", this.refresh);
13023 this.store.un("add", this.onAdd);
13024 this.store.un("remove", this.onRemove);
13025 this.store.un("update", this.onUpdate);
13026 this.store.un("clear", this.refresh);
13027 this.store.un("beforeload", this.onBeforeLoad);
13028 this.store.un("load", this.onLoad);
13029 this.store.un("loadexception", this.onLoad);
13033 store.on("datachanged", this.refresh, this);
13034 store.on("add", this.onAdd, this);
13035 store.on("remove", this.onRemove, this);
13036 store.on("update", this.onUpdate, this);
13037 store.on("clear", this.refresh, this);
13038 store.on("beforeload", this.onBeforeLoad, this);
13039 store.on("load", this.onLoad, this);
13040 store.on("loadexception", this.onLoad, this);
13048 * onbeforeLoad - masks the loading area.
13051 onBeforeLoad : function(store,opts)
13053 //Roo.log('onBeforeLoad');
13055 this.el.update("");
13057 this.el.mask(this.mask ? this.mask : "Loading" );
13059 onLoad : function ()
13066 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13067 * @param {HTMLElement} node
13068 * @return {HTMLElement} The template node
13070 findItemFromChild : function(node){
13071 var el = this.dataName ?
13072 this.el.child('.roo-tpl-' + this.dataName,true) :
13075 if(!node || node.parentNode == el){
13078 var p = node.parentNode;
13079 while(p && p != el){
13080 if(p.parentNode == el){
13089 onClick : function(e){
13090 var item = this.findItemFromChild(e.getTarget());
13092 var index = this.indexOf(item);
13093 if(this.onItemClick(item, index, e) !== false){
13094 this.fireEvent("click", this, index, item, e);
13097 this.clearSelections();
13102 onContextMenu : function(e){
13103 var item = this.findItemFromChild(e.getTarget());
13105 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13110 onDblClick : function(e){
13111 var item = this.findItemFromChild(e.getTarget());
13113 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13117 onItemClick : function(item, index, e)
13119 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13122 if (this.toggleSelect) {
13123 var m = this.isSelected(item) ? 'unselect' : 'select';
13126 _t[m](item, true, false);
13129 if(this.multiSelect || this.singleSelect){
13130 if(this.multiSelect && e.shiftKey && this.lastSelection){
13131 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13133 this.select(item, this.multiSelect && e.ctrlKey);
13134 this.lastSelection = item;
13137 if(!this.tickable){
13138 e.preventDefault();
13146 * Get the number of selected nodes.
13149 getSelectionCount : function(){
13150 return this.selections.length;
13154 * Get the currently selected nodes.
13155 * @return {Array} An array of HTMLElements
13157 getSelectedNodes : function(){
13158 return this.selections;
13162 * Get the indexes of the selected nodes.
13165 getSelectedIndexes : function(){
13166 var indexes = [], s = this.selections;
13167 for(var i = 0, len = s.length; i < len; i++){
13168 indexes.push(s[i].nodeIndex);
13174 * Clear all selections
13175 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13177 clearSelections : function(suppressEvent){
13178 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13179 this.cmp.elements = this.selections;
13180 this.cmp.removeClass(this.selectedClass);
13181 this.selections = [];
13182 if(!suppressEvent){
13183 this.fireEvent("selectionchange", this, this.selections);
13189 * Returns true if the passed node is selected
13190 * @param {HTMLElement/Number} node The node or node index
13191 * @return {Boolean}
13193 isSelected : function(node){
13194 var s = this.selections;
13198 node = this.getNode(node);
13199 return s.indexOf(node) !== -1;
13204 * @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
13205 * @param {Boolean} keepExisting (optional) true to keep existing selections
13206 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13208 select : function(nodeInfo, keepExisting, suppressEvent){
13209 if(nodeInfo instanceof Array){
13211 this.clearSelections(true);
13213 for(var i = 0, len = nodeInfo.length; i < len; i++){
13214 this.select(nodeInfo[i], true, true);
13218 var node = this.getNode(nodeInfo);
13219 if(!node || this.isSelected(node)){
13220 return; // already selected.
13223 this.clearSelections(true);
13226 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13227 Roo.fly(node).addClass(this.selectedClass);
13228 this.selections.push(node);
13229 if(!suppressEvent){
13230 this.fireEvent("selectionchange", this, this.selections);
13238 * @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
13239 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13240 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13242 unselect : function(nodeInfo, keepExisting, suppressEvent)
13244 if(nodeInfo instanceof Array){
13245 Roo.each(this.selections, function(s) {
13246 this.unselect(s, nodeInfo);
13250 var node = this.getNode(nodeInfo);
13251 if(!node || !this.isSelected(node)){
13252 //Roo.log("not selected");
13253 return; // not selected.
13257 Roo.each(this.selections, function(s) {
13259 Roo.fly(node).removeClass(this.selectedClass);
13266 this.selections= ns;
13267 this.fireEvent("selectionchange", this, this.selections);
13271 * Gets a template node.
13272 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13273 * @return {HTMLElement} The node or null if it wasn't found
13275 getNode : function(nodeInfo){
13276 if(typeof nodeInfo == "string"){
13277 return document.getElementById(nodeInfo);
13278 }else if(typeof nodeInfo == "number"){
13279 return this.nodes[nodeInfo];
13285 * Gets a range template nodes.
13286 * @param {Number} startIndex
13287 * @param {Number} endIndex
13288 * @return {Array} An array of nodes
13290 getNodes : function(start, end){
13291 var ns = this.nodes;
13292 start = start || 0;
13293 end = typeof end == "undefined" ? ns.length - 1 : end;
13296 for(var i = start; i <= end; i++){
13300 for(var i = start; i >= end; i--){
13308 * Finds the index of the passed node
13309 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13310 * @return {Number} The index of the node or -1
13312 indexOf : function(node){
13313 node = this.getNode(node);
13314 if(typeof node.nodeIndex == "number"){
13315 return node.nodeIndex;
13317 var ns = this.nodes;
13318 for(var i = 0, len = ns.length; i < len; i++){
13329 * based on jquery fullcalendar
13333 Roo.bootstrap = Roo.bootstrap || {};
13335 * @class Roo.bootstrap.Calendar
13336 * @extends Roo.bootstrap.Component
13337 * Bootstrap Calendar class
13338 * @cfg {Boolean} loadMask (true|false) default false
13339 * @cfg {Object} header generate the user specific header of the calendar, default false
13342 * Create a new Container
13343 * @param {Object} config The config object
13348 Roo.bootstrap.Calendar = function(config){
13349 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13353 * Fires when a date is selected
13354 * @param {DatePicker} this
13355 * @param {Date} date The selected date
13359 * @event monthchange
13360 * Fires when the displayed month changes
13361 * @param {DatePicker} this
13362 * @param {Date} date The selected month
13364 'monthchange': true,
13366 * @event evententer
13367 * Fires when mouse over an event
13368 * @param {Calendar} this
13369 * @param {event} Event
13371 'evententer': true,
13373 * @event eventleave
13374 * Fires when the mouse leaves an
13375 * @param {Calendar} this
13378 'eventleave': true,
13380 * @event eventclick
13381 * Fires when the mouse click an
13382 * @param {Calendar} this
13391 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13394 * @cfg {Number} startDay
13395 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13403 getAutoCreate : function(){
13406 var fc_button = function(name, corner, style, content ) {
13407 return Roo.apply({},{
13409 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13411 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13414 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13425 style : 'width:100%',
13432 cls : 'fc-header-left',
13434 fc_button('prev', 'left', 'arrow', '‹' ),
13435 fc_button('next', 'right', 'arrow', '›' ),
13436 { tag: 'span', cls: 'fc-header-space' },
13437 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13445 cls : 'fc-header-center',
13449 cls: 'fc-header-title',
13452 html : 'month / year'
13460 cls : 'fc-header-right',
13462 /* fc_button('month', 'left', '', 'month' ),
13463 fc_button('week', '', '', 'week' ),
13464 fc_button('day', 'right', '', 'day' )
13476 header = this.header;
13479 var cal_heads = function() {
13481 // fixme - handle this.
13483 for (var i =0; i < Date.dayNames.length; i++) {
13484 var d = Date.dayNames[i];
13487 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13488 html : d.substring(0,3)
13492 ret[0].cls += ' fc-first';
13493 ret[6].cls += ' fc-last';
13496 var cal_cell = function(n) {
13499 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13504 cls: 'fc-day-number',
13508 cls: 'fc-day-content',
13512 style: 'position: relative;' // height: 17px;
13524 var cal_rows = function() {
13527 for (var r = 0; r < 6; r++) {
13534 for (var i =0; i < Date.dayNames.length; i++) {
13535 var d = Date.dayNames[i];
13536 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13539 row.cn[0].cls+=' fc-first';
13540 row.cn[0].cn[0].style = 'min-height:90px';
13541 row.cn[6].cls+=' fc-last';
13545 ret[0].cls += ' fc-first';
13546 ret[4].cls += ' fc-prev-last';
13547 ret[5].cls += ' fc-last';
13554 cls: 'fc-border-separate',
13555 style : 'width:100%',
13563 cls : 'fc-first fc-last',
13581 cls : 'fc-content',
13582 style : "position: relative;",
13585 cls : 'fc-view fc-view-month fc-grid',
13586 style : 'position: relative',
13587 unselectable : 'on',
13590 cls : 'fc-event-container',
13591 style : 'position:absolute;z-index:8;top:0;left:0;'
13609 initEvents : function()
13612 throw "can not find store for calendar";
13618 style: "text-align:center",
13622 style: "background-color:white;width:50%;margin:250 auto",
13626 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13637 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13639 var size = this.el.select('.fc-content', true).first().getSize();
13640 this.maskEl.setSize(size.width, size.height);
13641 this.maskEl.enableDisplayMode("block");
13642 if(!this.loadMask){
13643 this.maskEl.hide();
13646 this.store = Roo.factory(this.store, Roo.data);
13647 this.store.on('load', this.onLoad, this);
13648 this.store.on('beforeload', this.onBeforeLoad, this);
13652 this.cells = this.el.select('.fc-day',true);
13653 //Roo.log(this.cells);
13654 this.textNodes = this.el.query('.fc-day-number');
13655 this.cells.addClassOnOver('fc-state-hover');
13657 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13658 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13659 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13660 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13662 this.on('monthchange', this.onMonthChange, this);
13664 this.update(new Date().clearTime());
13667 resize : function() {
13668 var sz = this.el.getSize();
13670 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13671 this.el.select('.fc-day-content div',true).setHeight(34);
13676 showPrevMonth : function(e){
13677 this.update(this.activeDate.add("mo", -1));
13679 showToday : function(e){
13680 this.update(new Date().clearTime());
13683 showNextMonth : function(e){
13684 this.update(this.activeDate.add("mo", 1));
13688 showPrevYear : function(){
13689 this.update(this.activeDate.add("y", -1));
13693 showNextYear : function(){
13694 this.update(this.activeDate.add("y", 1));
13699 update : function(date)
13701 var vd = this.activeDate;
13702 this.activeDate = date;
13703 // if(vd && this.el){
13704 // var t = date.getTime();
13705 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13706 // Roo.log('using add remove');
13708 // this.fireEvent('monthchange', this, date);
13710 // this.cells.removeClass("fc-state-highlight");
13711 // this.cells.each(function(c){
13712 // if(c.dateValue == t){
13713 // c.addClass("fc-state-highlight");
13714 // setTimeout(function(){
13715 // try{c.dom.firstChild.focus();}catch(e){}
13725 var days = date.getDaysInMonth();
13727 var firstOfMonth = date.getFirstDateOfMonth();
13728 var startingPos = firstOfMonth.getDay()-this.startDay;
13730 if(startingPos < this.startDay){
13734 var pm = date.add(Date.MONTH, -1);
13735 var prevStart = pm.getDaysInMonth()-startingPos;
13737 this.cells = this.el.select('.fc-day',true);
13738 this.textNodes = this.el.query('.fc-day-number');
13739 this.cells.addClassOnOver('fc-state-hover');
13741 var cells = this.cells.elements;
13742 var textEls = this.textNodes;
13744 Roo.each(cells, function(cell){
13745 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13748 days += startingPos;
13750 // convert everything to numbers so it's fast
13751 var day = 86400000;
13752 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13755 //Roo.log(prevStart);
13757 var today = new Date().clearTime().getTime();
13758 var sel = date.clearTime().getTime();
13759 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13760 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13761 var ddMatch = this.disabledDatesRE;
13762 var ddText = this.disabledDatesText;
13763 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13764 var ddaysText = this.disabledDaysText;
13765 var format = this.format;
13767 var setCellClass = function(cal, cell){
13771 //Roo.log('set Cell Class');
13773 var t = d.getTime();
13777 cell.dateValue = t;
13779 cell.className += " fc-today";
13780 cell.className += " fc-state-highlight";
13781 cell.title = cal.todayText;
13784 // disable highlight in other month..
13785 //cell.className += " fc-state-highlight";
13790 cell.className = " fc-state-disabled";
13791 cell.title = cal.minText;
13795 cell.className = " fc-state-disabled";
13796 cell.title = cal.maxText;
13800 if(ddays.indexOf(d.getDay()) != -1){
13801 cell.title = ddaysText;
13802 cell.className = " fc-state-disabled";
13805 if(ddMatch && format){
13806 var fvalue = d.dateFormat(format);
13807 if(ddMatch.test(fvalue)){
13808 cell.title = ddText.replace("%0", fvalue);
13809 cell.className = " fc-state-disabled";
13813 if (!cell.initialClassName) {
13814 cell.initialClassName = cell.dom.className;
13817 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13822 for(; i < startingPos; i++) {
13823 textEls[i].innerHTML = (++prevStart);
13824 d.setDate(d.getDate()+1);
13826 cells[i].className = "fc-past fc-other-month";
13827 setCellClass(this, cells[i]);
13832 for(; i < days; i++){
13833 intDay = i - startingPos + 1;
13834 textEls[i].innerHTML = (intDay);
13835 d.setDate(d.getDate()+1);
13837 cells[i].className = ''; // "x-date-active";
13838 setCellClass(this, cells[i]);
13842 for(; i < 42; i++) {
13843 textEls[i].innerHTML = (++extraDays);
13844 d.setDate(d.getDate()+1);
13846 cells[i].className = "fc-future fc-other-month";
13847 setCellClass(this, cells[i]);
13850 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13852 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13854 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13855 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13857 if(totalRows != 6){
13858 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13859 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13862 this.fireEvent('monthchange', this, date);
13866 if(!this.internalRender){
13867 var main = this.el.dom.firstChild;
13868 var w = main.offsetWidth;
13869 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13870 Roo.fly(main).setWidth(w);
13871 this.internalRender = true;
13872 // opera does not respect the auto grow header center column
13873 // then, after it gets a width opera refuses to recalculate
13874 // without a second pass
13875 if(Roo.isOpera && !this.secondPass){
13876 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13877 this.secondPass = true;
13878 this.update.defer(10, this, [date]);
13885 findCell : function(dt) {
13886 dt = dt.clearTime().getTime();
13888 this.cells.each(function(c){
13889 //Roo.log("check " +c.dateValue + '?=' + dt);
13890 if(c.dateValue == dt){
13900 findCells : function(ev) {
13901 var s = ev.start.clone().clearTime().getTime();
13903 var e= ev.end.clone().clearTime().getTime();
13906 this.cells.each(function(c){
13907 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13909 if(c.dateValue > e){
13912 if(c.dateValue < s){
13921 // findBestRow: function(cells)
13925 // for (var i =0 ; i < cells.length;i++) {
13926 // ret = Math.max(cells[i].rows || 0,ret);
13933 addItem : function(ev)
13935 // look for vertical location slot in
13936 var cells = this.findCells(ev);
13938 // ev.row = this.findBestRow(cells);
13940 // work out the location.
13944 for(var i =0; i < cells.length; i++) {
13946 cells[i].row = cells[0].row;
13949 cells[i].row = cells[i].row + 1;
13959 if (crow.start.getY() == cells[i].getY()) {
13961 crow.end = cells[i];
13978 cells[0].events.push(ev);
13980 this.calevents.push(ev);
13983 clearEvents: function() {
13985 if(!this.calevents){
13989 Roo.each(this.cells.elements, function(c){
13995 Roo.each(this.calevents, function(e) {
13996 Roo.each(e.els, function(el) {
13997 el.un('mouseenter' ,this.onEventEnter, this);
13998 el.un('mouseleave' ,this.onEventLeave, this);
14003 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14009 renderEvents: function()
14013 this.cells.each(function(c) {
14022 if(c.row != c.events.length){
14023 r = 4 - (4 - (c.row - c.events.length));
14026 c.events = ev.slice(0, r);
14027 c.more = ev.slice(r);
14029 if(c.more.length && c.more.length == 1){
14030 c.events.push(c.more.pop());
14033 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14037 this.cells.each(function(c) {
14039 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14042 for (var e = 0; e < c.events.length; e++){
14043 var ev = c.events[e];
14044 var rows = ev.rows;
14046 for(var i = 0; i < rows.length; i++) {
14048 // how many rows should it span..
14051 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14052 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14054 unselectable : "on",
14057 cls: 'fc-event-inner',
14061 // cls: 'fc-event-time',
14062 // html : cells.length > 1 ? '' : ev.time
14066 cls: 'fc-event-title',
14067 html : String.format('{0}', ev.title)
14074 cls: 'ui-resizable-handle ui-resizable-e',
14075 html : '  '
14082 cfg.cls += ' fc-event-start';
14084 if ((i+1) == rows.length) {
14085 cfg.cls += ' fc-event-end';
14088 var ctr = _this.el.select('.fc-event-container',true).first();
14089 var cg = ctr.createChild(cfg);
14091 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14092 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14094 var r = (c.more.length) ? 1 : 0;
14095 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14096 cg.setWidth(ebox.right - sbox.x -2);
14098 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14099 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14100 cg.on('click', _this.onEventClick, _this, ev);
14111 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14112 style : 'position: absolute',
14113 unselectable : "on",
14116 cls: 'fc-event-inner',
14120 cls: 'fc-event-title',
14128 cls: 'ui-resizable-handle ui-resizable-e',
14129 html : '  '
14135 var ctr = _this.el.select('.fc-event-container',true).first();
14136 var cg = ctr.createChild(cfg);
14138 var sbox = c.select('.fc-day-content',true).first().getBox();
14139 var ebox = c.select('.fc-day-content',true).first().getBox();
14141 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14142 cg.setWidth(ebox.right - sbox.x -2);
14144 cg.on('click', _this.onMoreEventClick, _this, c.more);
14154 onEventEnter: function (e, el,event,d) {
14155 this.fireEvent('evententer', this, el, event);
14158 onEventLeave: function (e, el,event,d) {
14159 this.fireEvent('eventleave', this, el, event);
14162 onEventClick: function (e, el,event,d) {
14163 this.fireEvent('eventclick', this, el, event);
14166 onMonthChange: function () {
14170 onMoreEventClick: function(e, el, more)
14174 this.calpopover.placement = 'right';
14175 this.calpopover.setTitle('More');
14177 this.calpopover.setContent('');
14179 var ctr = this.calpopover.el.select('.popover-content', true).first();
14181 Roo.each(more, function(m){
14183 cls : 'fc-event-hori fc-event-draggable',
14186 var cg = ctr.createChild(cfg);
14188 cg.on('click', _this.onEventClick, _this, m);
14191 this.calpopover.show(el);
14196 onLoad: function ()
14198 this.calevents = [];
14201 if(this.store.getCount() > 0){
14202 this.store.data.each(function(d){
14205 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14206 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14207 time : d.data.start_time,
14208 title : d.data.title,
14209 description : d.data.description,
14210 venue : d.data.venue
14215 this.renderEvents();
14217 if(this.calevents.length && this.loadMask){
14218 this.maskEl.hide();
14222 onBeforeLoad: function()
14224 this.clearEvents();
14226 this.maskEl.show();
14240 * @class Roo.bootstrap.Popover
14241 * @extends Roo.bootstrap.Component
14242 * Bootstrap Popover class
14243 * @cfg {String} html contents of the popover (or false to use children..)
14244 * @cfg {String} title of popover (or false to hide)
14245 * @cfg {String} placement how it is placed
14246 * @cfg {String} trigger click || hover (or false to trigger manually)
14247 * @cfg {String} over what (parent or false to trigger manually.)
14248 * @cfg {Number} delay - delay before showing
14251 * Create a new Popover
14252 * @param {Object} config The config object
14255 Roo.bootstrap.Popover = function(config){
14256 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14259 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14261 title: 'Fill in a title',
14264 placement : 'right',
14265 trigger : 'hover', // hover
14271 can_build_overlaid : false,
14273 getChildContainer : function()
14275 return this.el.select('.popover-content',true).first();
14278 getAutoCreate : function(){
14279 Roo.log('make popover?');
14281 cls : 'popover roo-dynamic',
14282 style: 'display:block',
14288 cls : 'popover-inner',
14292 cls: 'popover-title',
14296 cls : 'popover-content',
14307 setTitle: function(str)
14309 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14311 setContent: function(str)
14313 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14315 // as it get's added to the bottom of the page.
14316 onRender : function(ct, position)
14318 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14320 var cfg = Roo.apply({}, this.getAutoCreate());
14324 cfg.cls += ' ' + this.cls;
14327 cfg.style = this.style;
14329 Roo.log("adding to ")
14330 this.el = Roo.get(document.body).createChild(cfg, position);
14336 initEvents : function()
14338 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14339 this.el.enableDisplayMode('block');
14341 if (this.over === false) {
14344 if (this.triggers === false) {
14347 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14348 var triggers = this.trigger ? this.trigger.split(' ') : [];
14349 Roo.each(triggers, function(trigger) {
14351 if (trigger == 'click') {
14352 on_el.on('click', this.toggle, this);
14353 } else if (trigger != 'manual') {
14354 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14355 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14357 on_el.on(eventIn ,this.enter, this);
14358 on_el.on(eventOut, this.leave, this);
14369 toggle : function () {
14370 this.hoverState == 'in' ? this.leave() : this.enter();
14373 enter : function () {
14376 clearTimeout(this.timeout);
14378 this.hoverState = 'in';
14380 if (!this.delay || !this.delay.show) {
14385 this.timeout = setTimeout(function () {
14386 if (_t.hoverState == 'in') {
14389 }, this.delay.show)
14391 leave : function() {
14392 clearTimeout(this.timeout);
14394 this.hoverState = 'out';
14396 if (!this.delay || !this.delay.hide) {
14401 this.timeout = setTimeout(function () {
14402 if (_t.hoverState == 'out') {
14405 }, this.delay.hide)
14408 show : function (on_el)
14411 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14414 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14415 if (this.html !== false) {
14416 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14418 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14419 if (!this.title.length) {
14420 this.el.select('.popover-title',true).hide();
14423 var placement = typeof this.placement == 'function' ?
14424 this.placement.call(this, this.el, on_el) :
14427 var autoToken = /\s?auto?\s?/i;
14428 var autoPlace = autoToken.test(placement);
14430 placement = placement.replace(autoToken, '') || 'top';
14434 //this.el.setXY([0,0]);
14436 this.el.dom.style.display='block';
14437 this.el.addClass(placement);
14439 //this.el.appendTo(on_el);
14441 var p = this.getPosition();
14442 var box = this.el.getBox();
14447 var align = Roo.bootstrap.Popover.alignment[placement];
14448 this.el.alignTo(on_el, align[0],align[1]);
14449 //var arrow = this.el.select('.arrow',true).first();
14450 //arrow.set(align[2],
14452 this.el.addClass('in');
14453 this.hoverState = null;
14455 if (this.el.hasClass('fade')) {
14462 this.el.setXY([0,0]);
14463 this.el.removeClass('in');
14470 Roo.bootstrap.Popover.alignment = {
14471 'left' : ['r-l', [-10,0], 'right'],
14472 'right' : ['l-r', [10,0], 'left'],
14473 'bottom' : ['t-b', [0,10], 'top'],
14474 'top' : [ 'b-t', [0,-10], 'bottom']
14485 * @class Roo.bootstrap.Progress
14486 * @extends Roo.bootstrap.Component
14487 * Bootstrap Progress class
14488 * @cfg {Boolean} striped striped of the progress bar
14489 * @cfg {Boolean} active animated of the progress bar
14493 * Create a new Progress
14494 * @param {Object} config The config object
14497 Roo.bootstrap.Progress = function(config){
14498 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14501 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14506 getAutoCreate : function(){
14514 cfg.cls += ' progress-striped';
14518 cfg.cls += ' active';
14537 * @class Roo.bootstrap.ProgressBar
14538 * @extends Roo.bootstrap.Component
14539 * Bootstrap ProgressBar class
14540 * @cfg {Number} aria_valuenow aria-value now
14541 * @cfg {Number} aria_valuemin aria-value min
14542 * @cfg {Number} aria_valuemax aria-value max
14543 * @cfg {String} label label for the progress bar
14544 * @cfg {String} panel (success | info | warning | danger )
14545 * @cfg {String} role role of the progress bar
14546 * @cfg {String} sr_only text
14550 * Create a new ProgressBar
14551 * @param {Object} config The config object
14554 Roo.bootstrap.ProgressBar = function(config){
14555 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14558 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14562 aria_valuemax : 100,
14568 getAutoCreate : function()
14573 cls: 'progress-bar',
14574 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14586 cfg.role = this.role;
14589 if(this.aria_valuenow){
14590 cfg['aria-valuenow'] = this.aria_valuenow;
14593 if(this.aria_valuemin){
14594 cfg['aria-valuemin'] = this.aria_valuemin;
14597 if(this.aria_valuemax){
14598 cfg['aria-valuemax'] = this.aria_valuemax;
14601 if(this.label && !this.sr_only){
14602 cfg.html = this.label;
14606 cfg.cls += ' progress-bar-' + this.panel;
14612 update : function(aria_valuenow)
14614 this.aria_valuenow = aria_valuenow;
14616 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14631 * @class Roo.bootstrap.TabGroup
14632 * @extends Roo.bootstrap.Column
14633 * Bootstrap Column class
14634 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14635 * @cfg {Boolean} carousel true to make the group behave like a carousel
14636 * @cfg {Number} bullets show the panel pointer.. default 0
14637 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14638 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14639 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14642 * Create a new TabGroup
14643 * @param {Object} config The config object
14646 Roo.bootstrap.TabGroup = function(config){
14647 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14649 this.navId = Roo.id();
14652 Roo.bootstrap.TabGroup.register(this);
14656 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14659 transition : false,
14664 slideOnTouch : false,
14666 getAutoCreate : function()
14668 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14670 cfg.cls += ' tab-content';
14672 Roo.log('get auto create...............');
14674 if (this.carousel) {
14675 cfg.cls += ' carousel slide';
14678 cls : 'carousel-inner'
14681 if(this.bullets > 0 && !Roo.isTouch){
14684 cls : 'carousel-bullets',
14688 if(this.bullets_cls){
14689 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14692 for (var i = 0; i < this.bullets; i++){
14694 cls : 'bullet bullet-' + i
14702 cfg.cn[0].cn = bullets;
14709 initEvents: function()
14711 Roo.log('-------- init events on tab group ---------');
14713 if(this.bullets > 0 && !Roo.isTouch){
14719 if(Roo.isTouch && this.slideOnTouch){
14720 this.el.on("touchstart", this.onTouchStart, this);
14723 if(this.autoslide){
14726 this.slideFn = window.setInterval(function() {
14727 _this.showPanelNext();
14733 onTouchStart : function(e, el, o)
14735 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14739 this.showPanelNext();
14742 getChildContainer : function()
14744 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14748 * register a Navigation item
14749 * @param {Roo.bootstrap.NavItem} the navitem to add
14751 register : function(item)
14753 this.tabs.push( item);
14754 item.navId = this.navId; // not really needed..
14758 getActivePanel : function()
14761 Roo.each(this.tabs, function(t) {
14771 getPanelByName : function(n)
14774 Roo.each(this.tabs, function(t) {
14775 if (t.tabId == n) {
14783 indexOfPanel : function(p)
14786 Roo.each(this.tabs, function(t,i) {
14787 if (t.tabId == p.tabId) {
14796 * show a specific panel
14797 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14798 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14800 showPanel : function (pan)
14802 if(this.transition){
14803 Roo.log("waiting for the transitionend");
14807 if (typeof(pan) == 'number') {
14808 pan = this.tabs[pan];
14810 if (typeof(pan) == 'string') {
14811 pan = this.getPanelByName(pan);
14813 if (pan.tabId == this.getActivePanel().tabId) {
14816 var cur = this.getActivePanel();
14818 if (false === cur.fireEvent('beforedeactivate')) {
14822 if(this.bullets > 0 && !Roo.isTouch){
14823 this.setActiveBullet(this.indexOfPanel(pan));
14826 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14828 this.transition = true;
14829 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14830 var lr = dir == 'next' ? 'left' : 'right';
14831 pan.el.addClass(dir); // or prev
14832 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14833 cur.el.addClass(lr); // or right
14834 pan.el.addClass(lr);
14837 cur.el.on('transitionend', function() {
14838 Roo.log("trans end?");
14840 pan.el.removeClass([lr,dir]);
14841 pan.setActive(true);
14843 cur.el.removeClass([lr]);
14844 cur.setActive(false);
14846 _this.transition = false;
14848 }, this, { single: true } );
14853 cur.setActive(false);
14854 pan.setActive(true);
14859 showPanelNext : function()
14861 var i = this.indexOfPanel(this.getActivePanel());
14863 if (i >= this.tabs.length - 1 && !this.autoslide) {
14867 if (i >= this.tabs.length - 1 && this.autoslide) {
14871 this.showPanel(this.tabs[i+1]);
14874 showPanelPrev : function()
14876 var i = this.indexOfPanel(this.getActivePanel());
14878 if (i < 1 && !this.autoslide) {
14882 if (i < 1 && this.autoslide) {
14883 i = this.tabs.length;
14886 this.showPanel(this.tabs[i-1]);
14889 initBullet : function()
14897 for (var i = 0; i < this.bullets; i++){
14898 var bullet = this.el.select('.bullet-' + i, true).first();
14904 bullet.on('click', (function(e, el, o, ii, t){
14906 e.preventDefault();
14908 _this.showPanel(ii);
14910 if(_this.autoslide && _this.slideFn){
14911 clearInterval(_this.slideFn);
14912 _this.slideFn = window.setInterval(function() {
14913 _this.showPanelNext();
14917 }).createDelegate(this, [i, bullet], true));
14921 setActiveBullet : function(i)
14927 Roo.each(this.el.select('.bullet', true).elements, function(el){
14928 el.removeClass('selected');
14931 var bullet = this.el.select('.bullet-' + i, true).first();
14937 bullet.addClass('selected');
14948 Roo.apply(Roo.bootstrap.TabGroup, {
14952 * register a Navigation Group
14953 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14955 register : function(navgrp)
14957 this.groups[navgrp.navId] = navgrp;
14961 * fetch a Navigation Group based on the navigation ID
14962 * if one does not exist , it will get created.
14963 * @param {string} the navgroup to add
14964 * @returns {Roo.bootstrap.NavGroup} the navgroup
14966 get: function(navId) {
14967 if (typeof(this.groups[navId]) == 'undefined') {
14968 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14970 return this.groups[navId] ;
14985 * @class Roo.bootstrap.TabPanel
14986 * @extends Roo.bootstrap.Component
14987 * Bootstrap TabPanel class
14988 * @cfg {Boolean} active panel active
14989 * @cfg {String} html panel content
14990 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14991 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14995 * Create a new TabPanel
14996 * @param {Object} config The config object
14999 Roo.bootstrap.TabPanel = function(config){
15000 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15004 * Fires when the active status changes
15005 * @param {Roo.bootstrap.TabPanel} this
15006 * @param {Boolean} state the new state
15011 * @event beforedeactivate
15012 * Fires before a tab is de-activated - can be used to do validation on a form.
15013 * @param {Roo.bootstrap.TabPanel} this
15014 * @return {Boolean} false if there is an error
15017 'beforedeactivate': true
15020 this.tabId = this.tabId || Roo.id();
15024 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15031 getAutoCreate : function(){
15034 // item is needed for carousel - not sure if it has any effect otherwise
15035 cls: 'tab-pane item',
15036 html: this.html || ''
15040 cfg.cls += ' active';
15044 cfg.tabId = this.tabId;
15051 initEvents: function()
15053 Roo.log('-------- init events on tab panel ---------');
15055 var p = this.parent();
15056 this.navId = this.navId || p.navId;
15058 if (typeof(this.navId) != 'undefined') {
15059 // not really needed.. but just in case.. parent should be a NavGroup.
15060 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15061 Roo.log(['register', tg, this]);
15064 var i = tg.tabs.length - 1;
15066 if(this.active && tg.bullets > 0 && i < tg.bullets){
15067 tg.setActiveBullet(i);
15074 onRender : function(ct, position)
15076 // Roo.log("Call onRender: " + this.xtype);
15078 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15086 setActive: function(state)
15088 Roo.log("panel - set active " + this.tabId + "=" + state);
15090 this.active = state;
15092 this.el.removeClass('active');
15094 } else if (!this.el.hasClass('active')) {
15095 this.el.addClass('active');
15098 this.fireEvent('changed', this, state);
15115 * @class Roo.bootstrap.DateField
15116 * @extends Roo.bootstrap.Input
15117 * Bootstrap DateField class
15118 * @cfg {Number} weekStart default 0
15119 * @cfg {String} viewMode default empty, (months|years)
15120 * @cfg {String} minViewMode default empty, (months|years)
15121 * @cfg {Number} startDate default -Infinity
15122 * @cfg {Number} endDate default Infinity
15123 * @cfg {Boolean} todayHighlight default false
15124 * @cfg {Boolean} todayBtn default false
15125 * @cfg {Boolean} calendarWeeks default false
15126 * @cfg {Object} daysOfWeekDisabled default empty
15127 * @cfg {Boolean} singleMode default false (true | false)
15129 * @cfg {Boolean} keyboardNavigation default true
15130 * @cfg {String} language default en
15133 * Create a new DateField
15134 * @param {Object} config The config object
15137 Roo.bootstrap.DateField = function(config){
15138 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15142 * Fires when this field show.
15143 * @param {Roo.bootstrap.DateField} this
15144 * @param {Mixed} date The date value
15149 * Fires when this field hide.
15150 * @param {Roo.bootstrap.DateField} this
15151 * @param {Mixed} date The date value
15156 * Fires when select a date.
15157 * @param {Roo.bootstrap.DateField} this
15158 * @param {Mixed} date The date value
15164 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15167 * @cfg {String} format
15168 * The default date format string which can be overriden for localization support. The format must be
15169 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15173 * @cfg {String} altFormats
15174 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15175 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15177 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15185 todayHighlight : false,
15191 keyboardNavigation: true,
15193 calendarWeeks: false,
15195 startDate: -Infinity,
15199 daysOfWeekDisabled: [],
15203 singleMode : false,
15205 UTCDate: function()
15207 return new Date(Date.UTC.apply(Date, arguments));
15210 UTCToday: function()
15212 var today = new Date();
15213 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15216 getDate: function() {
15217 var d = this.getUTCDate();
15218 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15221 getUTCDate: function() {
15225 setDate: function(d) {
15226 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15229 setUTCDate: function(d) {
15231 this.setValue(this.formatDate(this.date));
15234 onRender: function(ct, position)
15237 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15239 this.language = this.language || 'en';
15240 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15241 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15243 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15244 this.format = this.format || 'm/d/y';
15245 this.isInline = false;
15246 this.isInput = true;
15247 this.component = this.el.select('.add-on', true).first() || false;
15248 this.component = (this.component && this.component.length === 0) ? false : this.component;
15249 this.hasInput = this.component && this.inputEL().length;
15251 if (typeof(this.minViewMode === 'string')) {
15252 switch (this.minViewMode) {
15254 this.minViewMode = 1;
15257 this.minViewMode = 2;
15260 this.minViewMode = 0;
15265 if (typeof(this.viewMode === 'string')) {
15266 switch (this.viewMode) {
15279 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15281 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15283 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15285 this.picker().on('mousedown', this.onMousedown, this);
15286 this.picker().on('click', this.onClick, this);
15288 this.picker().addClass('datepicker-dropdown');
15290 this.startViewMode = this.viewMode;
15292 if(this.singleMode){
15293 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15294 v.setVisibilityMode(Roo.Element.DISPLAY)
15298 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15299 v.setStyle('width', '189px');
15303 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15304 if(!this.calendarWeeks){
15309 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15310 v.attr('colspan', function(i, val){
15311 return parseInt(val) + 1;
15316 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15318 this.setStartDate(this.startDate);
15319 this.setEndDate(this.endDate);
15321 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15328 if(this.isInline) {
15333 picker : function()
15335 return this.pickerEl;
15336 // return this.el.select('.datepicker', true).first();
15339 fillDow: function()
15341 var dowCnt = this.weekStart;
15350 if(this.calendarWeeks){
15358 while (dowCnt < this.weekStart + 7) {
15362 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15366 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15369 fillMonths: function()
15372 var months = this.picker().select('>.datepicker-months td', true).first();
15374 months.dom.innerHTML = '';
15380 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15383 months.createChild(month);
15390 this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
15392 if (this.date < this.startDate) {
15393 this.viewDate = new Date(this.startDate);
15394 } else if (this.date > this.endDate) {
15395 this.viewDate = new Date(this.endDate);
15397 this.viewDate = new Date(this.date);
15405 var d = new Date(this.viewDate),
15406 year = d.getUTCFullYear(),
15407 month = d.getUTCMonth(),
15408 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15409 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15410 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15411 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15412 currentDate = this.date && this.date.valueOf(),
15413 today = this.UTCToday();
15415 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15417 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15419 // this.picker.select('>tfoot th.today').
15420 // .text(dates[this.language].today)
15421 // .toggle(this.todayBtn !== false);
15423 this.updateNavArrows();
15426 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15428 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15430 prevMonth.setUTCDate(day);
15432 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15434 var nextMonth = new Date(prevMonth);
15436 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15438 nextMonth = nextMonth.valueOf();
15440 var fillMonths = false;
15442 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15444 while(prevMonth.valueOf() < nextMonth) {
15447 if (prevMonth.getUTCDay() === this.weekStart) {
15449 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15457 if(this.calendarWeeks){
15458 // ISO 8601: First week contains first thursday.
15459 // ISO also states week starts on Monday, but we can be more abstract here.
15461 // Start of current week: based on weekstart/current date
15462 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15463 // Thursday of this week
15464 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15465 // First Thursday of year, year from thursday
15466 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15467 // Calendar week: ms between thursdays, div ms per day, div 7 days
15468 calWeek = (th - yth) / 864e5 / 7 + 1;
15470 fillMonths.cn.push({
15478 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15480 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15483 if (this.todayHighlight &&
15484 prevMonth.getUTCFullYear() == today.getFullYear() &&
15485 prevMonth.getUTCMonth() == today.getMonth() &&
15486 prevMonth.getUTCDate() == today.getDate()) {
15487 clsName += ' today';
15490 if (currentDate && prevMonth.valueOf() === currentDate) {
15491 clsName += ' active';
15494 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15495 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15496 clsName += ' disabled';
15499 fillMonths.cn.push({
15501 cls: 'day ' + clsName,
15502 html: prevMonth.getDate()
15505 prevMonth.setDate(prevMonth.getDate()+1);
15508 var currentYear = this.date && this.date.getUTCFullYear();
15509 var currentMonth = this.date && this.date.getUTCMonth();
15511 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15513 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15514 v.removeClass('active');
15516 if(currentYear === year && k === currentMonth){
15517 v.addClass('active');
15520 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15521 v.addClass('disabled');
15527 year = parseInt(year/10, 10) * 10;
15529 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15531 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15534 for (var i = -1; i < 11; i++) {
15535 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15537 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15545 showMode: function(dir)
15548 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15551 Roo.each(this.picker().select('>div',true).elements, function(v){
15552 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15555 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15560 if(this.isInline) return;
15562 this.picker().removeClass(['bottom', 'top']);
15564 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15566 * place to the top of element!
15570 this.picker().addClass('top');
15571 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15576 this.picker().addClass('bottom');
15578 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15581 parseDate : function(value)
15583 if(!value || value instanceof Date){
15586 var v = Date.parseDate(value, this.format);
15587 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15588 v = Date.parseDate(value, 'Y-m-d');
15590 if(!v && this.altFormats){
15591 if(!this.altFormatsArray){
15592 this.altFormatsArray = this.altFormats.split("|");
15594 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15595 v = Date.parseDate(value, this.altFormatsArray[i]);
15601 formatDate : function(date, fmt)
15603 return (!date || !(date instanceof Date)) ?
15604 date : date.dateFormat(fmt || this.format);
15607 onFocus : function()
15609 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15613 onBlur : function()
15615 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15617 var d = this.inputEl().getValue();
15626 this.picker().show();
15630 this.fireEvent('show', this, this.date);
15635 if(this.isInline) return;
15636 this.picker().hide();
15637 this.viewMode = this.startViewMode;
15640 this.fireEvent('hide', this, this.date);
15644 onMousedown: function(e)
15646 e.stopPropagation();
15647 e.preventDefault();
15652 Roo.bootstrap.DateField.superclass.keyup.call(this);
15656 setValue: function(v)
15659 // v can be a string or a date..
15662 var d = new Date(this.parseDate(v) ).clearTime();
15664 if(isNaN(d.getTime())){
15665 this.date = this.viewDate = '';
15666 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15670 v = this.formatDate(d);
15672 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15674 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15678 this.fireEvent('select', this, this.date);
15682 getValue: function()
15684 return this.formatDate(this.date);
15687 fireKey: function(e)
15689 if (!this.picker().isVisible()){
15690 if (e.keyCode == 27) // allow escape to hide and re-show picker
15695 var dateChanged = false,
15697 newDate, newViewDate;
15702 e.preventDefault();
15706 if (!this.keyboardNavigation) break;
15707 dir = e.keyCode == 37 ? -1 : 1;
15710 newDate = this.moveYear(this.date, dir);
15711 newViewDate = this.moveYear(this.viewDate, dir);
15712 } else if (e.shiftKey){
15713 newDate = this.moveMonth(this.date, dir);
15714 newViewDate = this.moveMonth(this.viewDate, dir);
15716 newDate = new Date(this.date);
15717 newDate.setUTCDate(this.date.getUTCDate() + dir);
15718 newViewDate = new Date(this.viewDate);
15719 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15721 if (this.dateWithinRange(newDate)){
15722 this.date = newDate;
15723 this.viewDate = newViewDate;
15724 this.setValue(this.formatDate(this.date));
15726 e.preventDefault();
15727 dateChanged = true;
15732 if (!this.keyboardNavigation) break;
15733 dir = e.keyCode == 38 ? -1 : 1;
15735 newDate = this.moveYear(this.date, dir);
15736 newViewDate = this.moveYear(this.viewDate, dir);
15737 } else if (e.shiftKey){
15738 newDate = this.moveMonth(this.date, dir);
15739 newViewDate = this.moveMonth(this.viewDate, dir);
15741 newDate = new Date(this.date);
15742 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15743 newViewDate = new Date(this.viewDate);
15744 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15746 if (this.dateWithinRange(newDate)){
15747 this.date = newDate;
15748 this.viewDate = newViewDate;
15749 this.setValue(this.formatDate(this.date));
15751 e.preventDefault();
15752 dateChanged = true;
15756 this.setValue(this.formatDate(this.date));
15758 e.preventDefault();
15761 this.setValue(this.formatDate(this.date));
15775 onClick: function(e)
15777 e.stopPropagation();
15778 e.preventDefault();
15780 var target = e.getTarget();
15782 if(target.nodeName.toLowerCase() === 'i'){
15783 target = Roo.get(target).dom.parentNode;
15786 var nodeName = target.nodeName;
15787 var className = target.className;
15788 var html = target.innerHTML;
15789 //Roo.log(nodeName);
15791 switch(nodeName.toLowerCase()) {
15793 switch(className) {
15799 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15800 switch(this.viewMode){
15802 this.viewDate = this.moveMonth(this.viewDate, dir);
15806 this.viewDate = this.moveYear(this.viewDate, dir);
15812 var date = new Date();
15813 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15815 this.setValue(this.formatDate(this.date));
15822 if (className.indexOf('disabled') < 0) {
15823 this.viewDate.setUTCDate(1);
15824 if (className.indexOf('month') > -1) {
15825 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15827 var year = parseInt(html, 10) || 0;
15828 this.viewDate.setUTCFullYear(year);
15832 if(this.singleMode){
15833 this.setValue(this.formatDate(this.viewDate));
15844 //Roo.log(className);
15845 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15846 var day = parseInt(html, 10) || 1;
15847 var year = this.viewDate.getUTCFullYear(),
15848 month = this.viewDate.getUTCMonth();
15850 if (className.indexOf('old') > -1) {
15857 } else if (className.indexOf('new') > -1) {
15865 //Roo.log([year,month,day]);
15866 this.date = this.UTCDate(year, month, day,0,0,0,0);
15867 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15869 //Roo.log(this.formatDate(this.date));
15870 this.setValue(this.formatDate(this.date));
15877 setStartDate: function(startDate)
15879 this.startDate = startDate || -Infinity;
15880 if (this.startDate !== -Infinity) {
15881 this.startDate = this.parseDate(this.startDate);
15884 this.updateNavArrows();
15887 setEndDate: function(endDate)
15889 this.endDate = endDate || Infinity;
15890 if (this.endDate !== Infinity) {
15891 this.endDate = this.parseDate(this.endDate);
15894 this.updateNavArrows();
15897 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15899 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15900 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15901 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15903 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15904 return parseInt(d, 10);
15907 this.updateNavArrows();
15910 updateNavArrows: function()
15912 if(this.singleMode){
15916 var d = new Date(this.viewDate),
15917 year = d.getUTCFullYear(),
15918 month = d.getUTCMonth();
15920 Roo.each(this.picker().select('.prev', true).elements, function(v){
15922 switch (this.viewMode) {
15925 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15931 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15938 Roo.each(this.picker().select('.next', true).elements, function(v){
15940 switch (this.viewMode) {
15943 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15949 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15957 moveMonth: function(date, dir)
15959 if (!dir) return date;
15960 var new_date = new Date(date.valueOf()),
15961 day = new_date.getUTCDate(),
15962 month = new_date.getUTCMonth(),
15963 mag = Math.abs(dir),
15965 dir = dir > 0 ? 1 : -1;
15968 // If going back one month, make sure month is not current month
15969 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15971 return new_date.getUTCMonth() == month;
15973 // If going forward one month, make sure month is as expected
15974 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15976 return new_date.getUTCMonth() != new_month;
15978 new_month = month + dir;
15979 new_date.setUTCMonth(new_month);
15980 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15981 if (new_month < 0 || new_month > 11)
15982 new_month = (new_month + 12) % 12;
15984 // For magnitudes >1, move one month at a time...
15985 for (var i=0; i<mag; i++)
15986 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15987 new_date = this.moveMonth(new_date, dir);
15988 // ...then reset the day, keeping it in the new month
15989 new_month = new_date.getUTCMonth();
15990 new_date.setUTCDate(day);
15992 return new_month != new_date.getUTCMonth();
15995 // Common date-resetting loop -- if date is beyond end of month, make it
15998 new_date.setUTCDate(--day);
15999 new_date.setUTCMonth(new_month);
16004 moveYear: function(date, dir)
16006 return this.moveMonth(date, dir*12);
16009 dateWithinRange: function(date)
16011 return date >= this.startDate && date <= this.endDate;
16017 this.picker().remove();
16022 Roo.apply(Roo.bootstrap.DateField, {
16033 html: '<i class="fa fa-arrow-left"/>'
16043 html: '<i class="fa fa-arrow-right"/>'
16085 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16086 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16087 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16088 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16089 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16102 navFnc: 'FullYear',
16107 navFnc: 'FullYear',
16112 Roo.apply(Roo.bootstrap.DateField, {
16116 cls: 'datepicker dropdown-menu roo-dynamic',
16120 cls: 'datepicker-days',
16124 cls: 'table-condensed',
16126 Roo.bootstrap.DateField.head,
16130 Roo.bootstrap.DateField.footer
16137 cls: 'datepicker-months',
16141 cls: 'table-condensed',
16143 Roo.bootstrap.DateField.head,
16144 Roo.bootstrap.DateField.content,
16145 Roo.bootstrap.DateField.footer
16152 cls: 'datepicker-years',
16156 cls: 'table-condensed',
16158 Roo.bootstrap.DateField.head,
16159 Roo.bootstrap.DateField.content,
16160 Roo.bootstrap.DateField.footer
16179 * @class Roo.bootstrap.TimeField
16180 * @extends Roo.bootstrap.Input
16181 * Bootstrap DateField class
16185 * Create a new TimeField
16186 * @param {Object} config The config object
16189 Roo.bootstrap.TimeField = function(config){
16190 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16194 * Fires when this field show.
16195 * @param {Roo.bootstrap.DateField} thisthis
16196 * @param {Mixed} date The date value
16201 * Fires when this field hide.
16202 * @param {Roo.bootstrap.DateField} this
16203 * @param {Mixed} date The date value
16208 * Fires when select a date.
16209 * @param {Roo.bootstrap.DateField} this
16210 * @param {Mixed} date The date value
16216 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16219 * @cfg {String} format
16220 * The default time format string which can be overriden for localization support. The format must be
16221 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16225 onRender: function(ct, position)
16228 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16230 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16232 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16234 this.pop = this.picker().select('>.datepicker-time',true).first();
16235 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16237 this.picker().on('mousedown', this.onMousedown, this);
16238 this.picker().on('click', this.onClick, this);
16240 this.picker().addClass('datepicker-dropdown');
16245 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16246 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16247 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16248 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16249 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16250 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16254 fireKey: function(e){
16255 if (!this.picker().isVisible()){
16256 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16262 e.preventDefault();
16270 this.onTogglePeriod();
16273 this.onIncrementMinutes();
16276 this.onDecrementMinutes();
16285 onClick: function(e) {
16286 e.stopPropagation();
16287 e.preventDefault();
16290 picker : function()
16292 return this.el.select('.datepicker', true).first();
16295 fillTime: function()
16297 var time = this.pop.select('tbody', true).first();
16299 time.dom.innerHTML = '';
16314 cls: 'hours-up glyphicon glyphicon-chevron-up'
16334 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16355 cls: 'timepicker-hour',
16370 cls: 'timepicker-minute',
16385 cls: 'btn btn-primary period',
16407 cls: 'hours-down glyphicon glyphicon-chevron-down'
16427 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16445 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16452 var hours = this.time.getHours();
16453 var minutes = this.time.getMinutes();
16466 hours = hours - 12;
16470 hours = '0' + hours;
16474 minutes = '0' + minutes;
16477 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16478 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16479 this.pop.select('button', true).first().dom.innerHTML = period;
16485 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16487 var cls = ['bottom'];
16489 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16496 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16501 this.picker().addClass(cls.join('-'));
16505 Roo.each(cls, function(c){
16507 _this.picker().setTop(_this.inputEl().getHeight());
16511 _this.picker().setTop(0 - _this.picker().getHeight());
16516 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16520 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16527 onFocus : function()
16529 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16533 onBlur : function()
16535 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16541 this.picker().show();
16546 this.fireEvent('show', this, this.date);
16551 this.picker().hide();
16554 this.fireEvent('hide', this, this.date);
16557 setTime : function()
16560 this.setValue(this.time.format(this.format));
16562 this.fireEvent('select', this, this.date);
16567 onMousedown: function(e){
16568 e.stopPropagation();
16569 e.preventDefault();
16572 onIncrementHours: function()
16574 Roo.log('onIncrementHours');
16575 this.time = this.time.add(Date.HOUR, 1);
16580 onDecrementHours: function()
16582 Roo.log('onDecrementHours');
16583 this.time = this.time.add(Date.HOUR, -1);
16587 onIncrementMinutes: function()
16589 Roo.log('onIncrementMinutes');
16590 this.time = this.time.add(Date.MINUTE, 1);
16594 onDecrementMinutes: function()
16596 Roo.log('onDecrementMinutes');
16597 this.time = this.time.add(Date.MINUTE, -1);
16601 onTogglePeriod: function()
16603 Roo.log('onTogglePeriod');
16604 this.time = this.time.add(Date.HOUR, 12);
16611 Roo.apply(Roo.bootstrap.TimeField, {
16641 cls: 'btn btn-info ok',
16653 Roo.apply(Roo.bootstrap.TimeField, {
16657 cls: 'datepicker dropdown-menu',
16661 cls: 'datepicker-time',
16665 cls: 'table-condensed',
16667 Roo.bootstrap.TimeField.content,
16668 Roo.bootstrap.TimeField.footer
16687 * @class Roo.bootstrap.MonthField
16688 * @extends Roo.bootstrap.Input
16689 * Bootstrap MonthField class
16691 * @cfg {String} language default en
16694 * Create a new MonthField
16695 * @param {Object} config The config object
16698 Roo.bootstrap.MonthField = function(config){
16699 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16704 * Fires when this field show.
16705 * @param {Roo.bootstrap.MonthField} this
16706 * @param {Mixed} date The date value
16711 * Fires when this field hide.
16712 * @param {Roo.bootstrap.MonthField} this
16713 * @param {Mixed} date The date value
16718 * Fires when select a date.
16719 * @param {Roo.bootstrap.MonthField} this
16720 * @param {String} oldvalue The old value
16721 * @param {String} newvalue The new value
16727 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16729 onRender: function(ct, position)
16732 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16734 this.language = this.language || 'en';
16735 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16736 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16738 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16739 this.isInline = false;
16740 this.isInput = true;
16741 this.component = this.el.select('.add-on', true).first() || false;
16742 this.component = (this.component && this.component.length === 0) ? false : this.component;
16743 this.hasInput = this.component && this.inputEL().length;
16745 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16747 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16749 this.picker().on('mousedown', this.onMousedown, this);
16750 this.picker().on('click', this.onClick, this);
16752 this.picker().addClass('datepicker-dropdown');
16754 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16755 v.setStyle('width', '189px');
16762 if(this.isInline) {
16768 setValue: function(v, suppressEvent)
16770 var o = this.getValue();
16772 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16776 if(suppressEvent !== true){
16777 this.fireEvent('select', this, o, v);
16782 getValue: function()
16787 onClick: function(e)
16789 e.stopPropagation();
16790 e.preventDefault();
16792 var target = e.getTarget();
16794 if(target.nodeName.toLowerCase() === 'i'){
16795 target = Roo.get(target).dom.parentNode;
16798 var nodeName = target.nodeName;
16799 var className = target.className;
16800 var html = target.innerHTML;
16802 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16806 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16808 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16814 picker : function()
16816 return this.pickerEl;
16819 fillMonths: function()
16822 var months = this.picker().select('>.datepicker-months td', true).first();
16824 months.dom.innerHTML = '';
16830 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16833 months.createChild(month);
16842 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16843 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16846 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16847 e.removeClass('active');
16849 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16850 e.addClass('active');
16857 if(this.isInline) return;
16859 this.picker().removeClass(['bottom', 'top']);
16861 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16863 * place to the top of element!
16867 this.picker().addClass('top');
16868 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16873 this.picker().addClass('bottom');
16875 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16878 onFocus : function()
16880 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16884 onBlur : function()
16886 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16888 var d = this.inputEl().getValue();
16897 this.picker().show();
16898 this.picker().select('>.datepicker-months', true).first().show();
16902 this.fireEvent('show', this, this.date);
16907 if(this.isInline) return;
16908 this.picker().hide();
16909 this.fireEvent('hide', this, this.date);
16913 onMousedown: function(e)
16915 e.stopPropagation();
16916 e.preventDefault();
16921 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16925 fireKey: function(e)
16927 if (!this.picker().isVisible()){
16928 if (e.keyCode == 27) // allow escape to hide and re-show picker
16938 e.preventDefault();
16942 dir = e.keyCode == 37 ? -1 : 1;
16944 this.vIndex = this.vIndex + dir;
16946 if(this.vIndex < 0){
16950 if(this.vIndex > 11){
16954 if(isNaN(this.vIndex)){
16958 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16964 dir = e.keyCode == 38 ? -1 : 1;
16966 this.vIndex = this.vIndex + dir * 4;
16968 if(this.vIndex < 0){
16972 if(this.vIndex > 11){
16976 if(isNaN(this.vIndex)){
16980 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16985 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16986 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16990 e.preventDefault();
16993 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16994 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17010 this.picker().remove();
17015 Roo.apply(Roo.bootstrap.MonthField, {
17034 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17035 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17040 Roo.apply(Roo.bootstrap.MonthField, {
17044 cls: 'datepicker dropdown-menu roo-dynamic',
17048 cls: 'datepicker-months',
17052 cls: 'table-condensed',
17054 Roo.bootstrap.DateField.content
17074 * @class Roo.bootstrap.CheckBox
17075 * @extends Roo.bootstrap.Input
17076 * Bootstrap CheckBox class
17078 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17079 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17080 * @cfg {String} boxLabel The text that appears beside the checkbox
17081 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17082 * @cfg {Boolean} checked initnal the element
17083 * @cfg {Boolean} inline inline the element (default false)
17084 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17087 * Create a new CheckBox
17088 * @param {Object} config The config object
17091 Roo.bootstrap.CheckBox = function(config){
17092 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17097 * Fires when the element is checked or unchecked.
17098 * @param {Roo.bootstrap.CheckBox} this This input
17099 * @param {Boolean} checked The new checked value
17106 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17108 inputType: 'checkbox',
17116 getAutoCreate : function()
17118 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17124 cfg.cls = 'form-group ' + this.inputType; //input-group
17127 cfg.cls += ' ' + this.inputType + '-inline';
17133 type : this.inputType,
17134 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17135 cls : 'roo-' + this.inputType, //'form-box',
17136 placeholder : this.placeholder || ''
17140 if (this.weight) { // Validity check?
17141 cfg.cls += " " + this.inputType + "-" + this.weight;
17144 if (this.disabled) {
17145 input.disabled=true;
17149 input.checked = this.checked;
17153 input.name = this.name;
17157 input.cls += ' input-' + this.size;
17162 ['xs','sm','md','lg'].map(function(size){
17163 if (settings[size]) {
17164 cfg.cls += ' col-' + size + '-' + settings[size];
17168 var inputblock = input;
17170 if (this.before || this.after) {
17173 cls : 'input-group',
17178 inputblock.cn.push({
17180 cls : 'input-group-addon',
17185 inputblock.cn.push(input);
17188 inputblock.cn.push({
17190 cls : 'input-group-addon',
17197 if (align ==='left' && this.fieldLabel.length) {
17198 Roo.log("left and has label");
17204 cls : 'control-label col-md-' + this.labelWidth,
17205 html : this.fieldLabel
17209 cls : "col-md-" + (12 - this.labelWidth),
17216 } else if ( this.fieldLabel.length) {
17221 tag: this.boxLabel ? 'span' : 'label',
17223 cls: 'control-label box-input-label',
17224 //cls : 'input-group-addon',
17225 html : this.fieldLabel
17235 Roo.log(" no label && no align");
17236 cfg.cn = [ inputblock ] ;
17241 var boxLabelCfg = {
17243 //'for': id, // box label is handled by onclick - so no for...
17245 html: this.boxLabel
17249 boxLabelCfg.tooltip = this.tooltip;
17252 cfg.cn.push(boxLabelCfg);
17262 * return the real input element.
17264 inputEl: function ()
17266 return this.el.select('input.roo-' + this.inputType,true).first();
17269 labelEl: function()
17271 return this.el.select('label.control-label',true).first();
17273 /* depricated... */
17277 return this.labelEl();
17280 initEvents : function()
17282 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17284 this.inputEl().on('click', this.onClick, this);
17286 if (this.boxLabel) {
17287 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17290 this.startValue = this.getValue();
17293 Roo.bootstrap.CheckBox.register(this);
17297 onClick : function()
17299 this.setChecked(!this.checked);
17302 setChecked : function(state,suppressEvent)
17304 this.startValue = this.getValue();
17306 if(this.inputType == 'radio'){
17308 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17309 e.dom.checked = false;
17312 this.inputEl().dom.checked = true;
17314 this.inputEl().dom.value = this.inputValue;
17316 if(suppressEvent !== true){
17317 this.fireEvent('check', this, true);
17325 this.checked = state;
17327 this.inputEl().dom.checked = state;
17329 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17331 if(suppressEvent !== true){
17332 this.fireEvent('check', this, state);
17338 getValue : function()
17340 if(this.inputType == 'radio'){
17341 return this.getGroupValue();
17344 return this.inputEl().getValue();
17348 getGroupValue : function()
17350 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17354 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17357 setValue : function(v,suppressEvent)
17359 if(this.inputType == 'radio'){
17360 this.setGroupValue(v, suppressEvent);
17364 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17369 setGroupValue : function(v, suppressEvent)
17371 this.startValue = this.getValue();
17373 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17374 e.dom.checked = false;
17376 if(e.dom.value == v){
17377 e.dom.checked = true;
17381 if(suppressEvent !== true){
17382 this.fireEvent('check', this, true);
17390 validate : function()
17394 (this.inputType == 'radio' && this.validateRadio()) ||
17395 (this.inputType == 'checkbox' && this.validateCheckbox())
17401 this.markInvalid();
17405 validateRadio : function()
17409 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17410 if(!e.dom.checked){
17422 validateCheckbox : function()
17425 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17428 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17436 for(var i in group){
17441 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17448 * Mark this field as valid
17450 markValid : function()
17452 if(this.allowBlank){
17458 this.fireEvent('valid', this);
17460 if(this.inputType == 'radio'){
17461 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17462 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17463 e.findParent('.form-group', false, true).addClass(_this.validClass);
17470 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17471 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17475 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17481 for(var i in group){
17482 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17483 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17488 * Mark this field as invalid
17489 * @param {String} msg The validation message
17491 markInvalid : function(msg)
17493 if(this.allowBlank){
17499 this.fireEvent('invalid', this, msg);
17501 if(this.inputType == 'radio'){
17502 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17503 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17504 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17511 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17512 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17516 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17522 for(var i in group){
17523 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17524 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17531 Roo.apply(Roo.bootstrap.CheckBox, {
17536 * register a CheckBox Group
17537 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17539 register : function(checkbox)
17541 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17542 this.groups[checkbox.groupId] = {};
17545 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17549 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17553 * fetch a CheckBox Group based on the group ID
17554 * @param {string} the group ID
17555 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17557 get: function(groupId) {
17558 if (typeof(this.groups[groupId]) == 'undefined') {
17562 return this.groups[groupId] ;
17574 *<div class="radio">
17576 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17577 Option one is this and that—be sure to include why it's great
17584 *<label class="radio-inline">fieldLabel</label>
17585 *<label class="radio-inline">
17586 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17594 * @class Roo.bootstrap.Radio
17595 * @extends Roo.bootstrap.CheckBox
17596 * Bootstrap Radio class
17599 * Create a new Radio
17600 * @param {Object} config The config object
17603 Roo.bootstrap.Radio = function(config){
17604 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17608 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17610 inputType: 'radio',
17614 getAutoCreate : function()
17616 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17617 align = align || 'left'; // default...
17624 tag : this.inline ? 'span' : 'div',
17629 var inline = this.inline ? ' radio-inline' : '';
17633 // does not need for, as we wrap the input with it..
17635 cls : 'control-label box-label' + inline,
17638 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17642 //cls : 'control-label' + inline,
17643 html : this.fieldLabel,
17644 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17653 type : this.inputType,
17654 //value : (!this.checked) ? this.valueOff : this.inputValue,
17655 value : this.inputValue,
17657 placeholder : this.placeholder || '' // ?? needed????
17660 if (this.weight) { // Validity check?
17661 input.cls += " radio-" + this.weight;
17663 if (this.disabled) {
17664 input.disabled=true;
17668 input.checked = this.checked;
17672 input.name = this.name;
17676 input.cls += ' input-' + this.size;
17679 //?? can span's inline have a width??
17682 ['xs','sm','md','lg'].map(function(size){
17683 if (settings[size]) {
17684 cfg.cls += ' col-' + size + '-' + settings[size];
17688 var inputblock = input;
17690 if (this.before || this.after) {
17693 cls : 'input-group',
17698 inputblock.cn.push({
17700 cls : 'input-group-addon',
17704 inputblock.cn.push(input);
17706 inputblock.cn.push({
17708 cls : 'input-group-addon',
17716 if (this.fieldLabel && this.fieldLabel.length) {
17717 cfg.cn.push(fieldLabel);
17720 // normal bootstrap puts the input inside the label.
17721 // however with our styled version - it has to go after the input.
17723 //lbl.cn.push(inputblock);
17727 cls: 'radio' + inline,
17734 cfg.cn.push( lblwrap);
17739 html: this.boxLabel
17748 initEvents : function()
17750 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17752 this.inputEl().on('click', this.onClick, this);
17753 if (this.boxLabel) {
17754 Roo.log('find label')
17755 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17760 inputEl: function ()
17762 return this.el.select('input.roo-radio',true).first();
17764 onClick : function()
17767 this.setChecked(true);
17770 setChecked : function(state,suppressEvent)
17773 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17774 v.dom.checked = false;
17777 Roo.log(this.inputEl().dom);
17778 this.checked = state;
17779 this.inputEl().dom.checked = state;
17781 if(suppressEvent !== true){
17782 this.fireEvent('check', this, state);
17785 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17789 getGroupValue : function()
17792 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17793 if(v.dom.checked == true){
17794 value = v.dom.value;
17802 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17803 * @return {Mixed} value The field value
17805 getValue : function(){
17806 return this.getGroupValue();
17812 //<script type="text/javascript">
17815 * Based Ext JS Library 1.1.1
17816 * Copyright(c) 2006-2007, Ext JS, LLC.
17822 * @class Roo.HtmlEditorCore
17823 * @extends Roo.Component
17824 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17826 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17829 Roo.HtmlEditorCore = function(config){
17832 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17837 * @event initialize
17838 * Fires when the editor is fully initialized (including the iframe)
17839 * @param {Roo.HtmlEditorCore} this
17844 * Fires when the editor is first receives the focus. Any insertion must wait
17845 * until after this event.
17846 * @param {Roo.HtmlEditorCore} this
17850 * @event beforesync
17851 * Fires before the textarea is updated with content from the editor iframe. Return false
17852 * to cancel the sync.
17853 * @param {Roo.HtmlEditorCore} this
17854 * @param {String} html
17858 * @event beforepush
17859 * Fires before the iframe editor is updated with content from the textarea. Return false
17860 * to cancel the push.
17861 * @param {Roo.HtmlEditorCore} this
17862 * @param {String} html
17867 * Fires when the textarea is updated with content from the editor iframe.
17868 * @param {Roo.HtmlEditorCore} this
17869 * @param {String} html
17874 * Fires when the iframe editor is updated with content from the textarea.
17875 * @param {Roo.HtmlEditorCore} this
17876 * @param {String} html
17881 * @event editorevent
17882 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17883 * @param {Roo.HtmlEditorCore} this
17889 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17891 // defaults : white / black...
17892 this.applyBlacklists();
17899 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17903 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17909 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17914 * @cfg {Number} height (in pixels)
17918 * @cfg {Number} width (in pixels)
17923 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17926 stylesheets: false,
17931 // private properties
17932 validationEvent : false,
17934 initialized : false,
17936 sourceEditMode : false,
17937 onFocus : Roo.emptyFn,
17939 hideMode:'offsets',
17943 // blacklist + whitelisted elements..
17950 * Protected method that will not generally be called directly. It
17951 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17952 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17954 getDocMarkup : function(){
17958 // inherit styels from page...??
17959 if (this.stylesheets === false) {
17961 Roo.get(document.head).select('style').each(function(node) {
17962 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17965 Roo.get(document.head).select('link').each(function(node) {
17966 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17969 } else if (!this.stylesheets.length) {
17971 st = '<style type="text/css">' +
17972 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17978 st += '<style type="text/css">' +
17979 'IMG { cursor: pointer } ' +
17983 return '<html><head>' + st +
17984 //<style type="text/css">' +
17985 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17987 ' </head><body class="roo-htmleditor-body"></body></html>';
17991 onRender : function(ct, position)
17994 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17995 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17998 this.el.dom.style.border = '0 none';
17999 this.el.dom.setAttribute('tabIndex', -1);
18000 this.el.addClass('x-hidden hide');
18004 if(Roo.isIE){ // fix IE 1px bogus margin
18005 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18009 this.frameId = Roo.id();
18013 var iframe = this.owner.wrap.createChild({
18015 cls: 'form-control', // bootstrap..
18017 name: this.frameId,
18018 frameBorder : 'no',
18019 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18024 this.iframe = iframe.dom;
18026 this.assignDocWin();
18028 this.doc.designMode = 'on';
18031 this.doc.write(this.getDocMarkup());
18035 var task = { // must defer to wait for browser to be ready
18037 //console.log("run task?" + this.doc.readyState);
18038 this.assignDocWin();
18039 if(this.doc.body || this.doc.readyState == 'complete'){
18041 this.doc.designMode="on";
18045 Roo.TaskMgr.stop(task);
18046 this.initEditor.defer(10, this);
18053 Roo.TaskMgr.start(task);
18058 onResize : function(w, h)
18060 Roo.log('resize: ' +w + ',' + h );
18061 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18065 if(typeof w == 'number'){
18067 this.iframe.style.width = w + 'px';
18069 if(typeof h == 'number'){
18071 this.iframe.style.height = h + 'px';
18073 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18080 * Toggles the editor between standard and source edit mode.
18081 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18083 toggleSourceEdit : function(sourceEditMode){
18085 this.sourceEditMode = sourceEditMode === true;
18087 if(this.sourceEditMode){
18089 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18092 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18093 //this.iframe.className = '';
18096 //this.setSize(this.owner.wrap.getSize());
18097 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18104 * Protected method that will not generally be called directly. If you need/want
18105 * custom HTML cleanup, this is the method you should override.
18106 * @param {String} html The HTML to be cleaned
18107 * return {String} The cleaned HTML
18109 cleanHtml : function(html){
18110 html = String(html);
18111 if(html.length > 5){
18112 if(Roo.isSafari){ // strip safari nonsense
18113 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18116 if(html == ' '){
18123 * HTML Editor -> Textarea
18124 * Protected method that will not generally be called directly. Syncs the contents
18125 * of the editor iframe with the textarea.
18127 syncValue : function(){
18128 if(this.initialized){
18129 var bd = (this.doc.body || this.doc.documentElement);
18130 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18131 var html = bd.innerHTML;
18133 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18134 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18136 html = '<div style="'+m[0]+'">' + html + '</div>';
18139 html = this.cleanHtml(html);
18140 // fix up the special chars.. normaly like back quotes in word...
18141 // however we do not want to do this with chinese..
18142 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18143 var cc = b.charCodeAt();
18145 (cc >= 0x4E00 && cc < 0xA000 ) ||
18146 (cc >= 0x3400 && cc < 0x4E00 ) ||
18147 (cc >= 0xf900 && cc < 0xfb00 )
18153 if(this.owner.fireEvent('beforesync', this, html) !== false){
18154 this.el.dom.value = html;
18155 this.owner.fireEvent('sync', this, html);
18161 * Protected method that will not generally be called directly. Pushes the value of the textarea
18162 * into the iframe editor.
18164 pushValue : function(){
18165 if(this.initialized){
18166 var v = this.el.dom.value.trim();
18168 // if(v.length < 1){
18172 if(this.owner.fireEvent('beforepush', this, v) !== false){
18173 var d = (this.doc.body || this.doc.documentElement);
18175 this.cleanUpPaste();
18176 this.el.dom.value = d.innerHTML;
18177 this.owner.fireEvent('push', this, v);
18183 deferFocus : function(){
18184 this.focus.defer(10, this);
18188 focus : function(){
18189 if(this.win && !this.sourceEditMode){
18196 assignDocWin: function()
18198 var iframe = this.iframe;
18201 this.doc = iframe.contentWindow.document;
18202 this.win = iframe.contentWindow;
18204 // if (!Roo.get(this.frameId)) {
18207 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18208 // this.win = Roo.get(this.frameId).dom.contentWindow;
18210 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18214 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18215 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18220 initEditor : function(){
18221 //console.log("INIT EDITOR");
18222 this.assignDocWin();
18226 this.doc.designMode="on";
18228 this.doc.write(this.getDocMarkup());
18231 var dbody = (this.doc.body || this.doc.documentElement);
18232 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18233 // this copies styles from the containing element into thsi one..
18234 // not sure why we need all of this..
18235 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18237 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18238 //ss['background-attachment'] = 'fixed'; // w3c
18239 dbody.bgProperties = 'fixed'; // ie
18240 //Roo.DomHelper.applyStyles(dbody, ss);
18241 Roo.EventManager.on(this.doc, {
18242 //'mousedown': this.onEditorEvent,
18243 'mouseup': this.onEditorEvent,
18244 'dblclick': this.onEditorEvent,
18245 'click': this.onEditorEvent,
18246 'keyup': this.onEditorEvent,
18251 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18253 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18254 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18256 this.initialized = true;
18258 this.owner.fireEvent('initialize', this);
18263 onDestroy : function(){
18269 //for (var i =0; i < this.toolbars.length;i++) {
18270 // // fixme - ask toolbars for heights?
18271 // this.toolbars[i].onDestroy();
18274 //this.wrap.dom.innerHTML = '';
18275 //this.wrap.remove();
18280 onFirstFocus : function(){
18282 this.assignDocWin();
18285 this.activated = true;
18288 if(Roo.isGecko){ // prevent silly gecko errors
18290 var s = this.win.getSelection();
18291 if(!s.focusNode || s.focusNode.nodeType != 3){
18292 var r = s.getRangeAt(0);
18293 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18298 this.execCmd('useCSS', true);
18299 this.execCmd('styleWithCSS', false);
18302 this.owner.fireEvent('activate', this);
18306 adjustFont: function(btn){
18307 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18308 //if(Roo.isSafari){ // safari
18311 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18312 if(Roo.isSafari){ // safari
18313 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18314 v = (v < 10) ? 10 : v;
18315 v = (v > 48) ? 48 : v;
18316 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18321 v = Math.max(1, v+adjust);
18323 this.execCmd('FontSize', v );
18326 onEditorEvent : function(e){
18327 this.owner.fireEvent('editorevent', this, e);
18328 // this.updateToolbar();
18329 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18332 insertTag : function(tg)
18334 // could be a bit smarter... -> wrap the current selected tRoo..
18335 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18337 range = this.createRange(this.getSelection());
18338 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18339 wrappingNode.appendChild(range.extractContents());
18340 range.insertNode(wrappingNode);
18347 this.execCmd("formatblock", tg);
18351 insertText : function(txt)
18355 var range = this.createRange();
18356 range.deleteContents();
18357 //alert(Sender.getAttribute('label'));
18359 range.insertNode(this.doc.createTextNode(txt));
18365 * Executes a Midas editor command on the editor document and performs necessary focus and
18366 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18367 * @param {String} cmd The Midas command
18368 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18370 relayCmd : function(cmd, value){
18372 this.execCmd(cmd, value);
18373 this.owner.fireEvent('editorevent', this);
18374 //this.updateToolbar();
18375 this.owner.deferFocus();
18379 * Executes a Midas editor command directly on the editor document.
18380 * For visual commands, you should use {@link #relayCmd} instead.
18381 * <b>This should only be called after the editor is initialized.</b>
18382 * @param {String} cmd The Midas command
18383 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18385 execCmd : function(cmd, value){
18386 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18393 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18395 * @param {String} text | dom node..
18397 insertAtCursor : function(text)
18402 if(!this.activated){
18408 var r = this.doc.selection.createRange();
18419 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18423 // from jquery ui (MIT licenced)
18425 var win = this.win;
18427 if (win.getSelection && win.getSelection().getRangeAt) {
18428 range = win.getSelection().getRangeAt(0);
18429 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18430 range.insertNode(node);
18431 } else if (win.document.selection && win.document.selection.createRange) {
18432 // no firefox support
18433 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18434 win.document.selection.createRange().pasteHTML(txt);
18436 // no firefox support
18437 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18438 this.execCmd('InsertHTML', txt);
18447 mozKeyPress : function(e){
18449 var c = e.getCharCode(), cmd;
18452 c = String.fromCharCode(c).toLowerCase();
18466 this.cleanUpPaste.defer(100, this);
18474 e.preventDefault();
18482 fixKeys : function(){ // load time branching for fastest keydown performance
18484 return function(e){
18485 var k = e.getKey(), r;
18488 r = this.doc.selection.createRange();
18491 r.pasteHTML('    ');
18498 r = this.doc.selection.createRange();
18500 var target = r.parentElement();
18501 if(!target || target.tagName.toLowerCase() != 'li'){
18503 r.pasteHTML('<br />');
18509 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18510 this.cleanUpPaste.defer(100, this);
18516 }else if(Roo.isOpera){
18517 return function(e){
18518 var k = e.getKey();
18522 this.execCmd('InsertHTML','    ');
18525 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18526 this.cleanUpPaste.defer(100, this);
18531 }else if(Roo.isSafari){
18532 return function(e){
18533 var k = e.getKey();
18537 this.execCmd('InsertText','\t');
18541 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18542 this.cleanUpPaste.defer(100, this);
18550 getAllAncestors: function()
18552 var p = this.getSelectedNode();
18555 a.push(p); // push blank onto stack..
18556 p = this.getParentElement();
18560 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18564 a.push(this.doc.body);
18568 lastSelNode : false,
18571 getSelection : function()
18573 this.assignDocWin();
18574 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18577 getSelectedNode: function()
18579 // this may only work on Gecko!!!
18581 // should we cache this!!!!
18586 var range = this.createRange(this.getSelection()).cloneRange();
18589 var parent = range.parentElement();
18591 var testRange = range.duplicate();
18592 testRange.moveToElementText(parent);
18593 if (testRange.inRange(range)) {
18596 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18599 parent = parent.parentElement;
18604 // is ancestor a text element.
18605 var ac = range.commonAncestorContainer;
18606 if (ac.nodeType == 3) {
18607 ac = ac.parentNode;
18610 var ar = ac.childNodes;
18613 var other_nodes = [];
18614 var has_other_nodes = false;
18615 for (var i=0;i<ar.length;i++) {
18616 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18619 // fullly contained node.
18621 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18626 // probably selected..
18627 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18628 other_nodes.push(ar[i]);
18632 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18637 has_other_nodes = true;
18639 if (!nodes.length && other_nodes.length) {
18640 nodes= other_nodes;
18642 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18648 createRange: function(sel)
18650 // this has strange effects when using with
18651 // top toolbar - not sure if it's a great idea.
18652 //this.editor.contentWindow.focus();
18653 if (typeof sel != "undefined") {
18655 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18657 return this.doc.createRange();
18660 return this.doc.createRange();
18663 getParentElement: function()
18666 this.assignDocWin();
18667 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18669 var range = this.createRange(sel);
18672 var p = range.commonAncestorContainer;
18673 while (p.nodeType == 3) { // text node
18684 * Range intersection.. the hard stuff...
18688 * [ -- selected range --- ]
18692 * if end is before start or hits it. fail.
18693 * if start is after end or hits it fail.
18695 * if either hits (but other is outside. - then it's not
18701 // @see http://www.thismuchiknow.co.uk/?p=64.
18702 rangeIntersectsNode : function(range, node)
18704 var nodeRange = node.ownerDocument.createRange();
18706 nodeRange.selectNode(node);
18708 nodeRange.selectNodeContents(node);
18711 var rangeStartRange = range.cloneRange();
18712 rangeStartRange.collapse(true);
18714 var rangeEndRange = range.cloneRange();
18715 rangeEndRange.collapse(false);
18717 var nodeStartRange = nodeRange.cloneRange();
18718 nodeStartRange.collapse(true);
18720 var nodeEndRange = nodeRange.cloneRange();
18721 nodeEndRange.collapse(false);
18723 return rangeStartRange.compareBoundaryPoints(
18724 Range.START_TO_START, nodeEndRange) == -1 &&
18725 rangeEndRange.compareBoundaryPoints(
18726 Range.START_TO_START, nodeStartRange) == 1;
18730 rangeCompareNode : function(range, node)
18732 var nodeRange = node.ownerDocument.createRange();
18734 nodeRange.selectNode(node);
18736 nodeRange.selectNodeContents(node);
18740 range.collapse(true);
18742 nodeRange.collapse(true);
18744 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18745 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18747 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18749 var nodeIsBefore = ss == 1;
18750 var nodeIsAfter = ee == -1;
18752 if (nodeIsBefore && nodeIsAfter)
18754 if (!nodeIsBefore && nodeIsAfter)
18755 return 1; //right trailed.
18757 if (nodeIsBefore && !nodeIsAfter)
18758 return 2; // left trailed.
18763 // private? - in a new class?
18764 cleanUpPaste : function()
18766 // cleans up the whole document..
18767 Roo.log('cleanuppaste');
18769 this.cleanUpChildren(this.doc.body);
18770 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18771 if (clean != this.doc.body.innerHTML) {
18772 this.doc.body.innerHTML = clean;
18777 cleanWordChars : function(input) {// change the chars to hex code
18778 var he = Roo.HtmlEditorCore;
18780 var output = input;
18781 Roo.each(he.swapCodes, function(sw) {
18782 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18784 output = output.replace(swapper, sw[1]);
18791 cleanUpChildren : function (n)
18793 if (!n.childNodes.length) {
18796 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18797 this.cleanUpChild(n.childNodes[i]);
18804 cleanUpChild : function (node)
18807 //console.log(node);
18808 if (node.nodeName == "#text") {
18809 // clean up silly Windows -- stuff?
18812 if (node.nodeName == "#comment") {
18813 node.parentNode.removeChild(node);
18814 // clean up silly Windows -- stuff?
18817 var lcname = node.tagName.toLowerCase();
18818 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18819 // whitelist of tags..
18821 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18823 node.parentNode.removeChild(node);
18828 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18830 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18831 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18833 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18834 // remove_keep_children = true;
18837 if (remove_keep_children) {
18838 this.cleanUpChildren(node);
18839 // inserts everything just before this node...
18840 while (node.childNodes.length) {
18841 var cn = node.childNodes[0];
18842 node.removeChild(cn);
18843 node.parentNode.insertBefore(cn, node);
18845 node.parentNode.removeChild(node);
18849 if (!node.attributes || !node.attributes.length) {
18850 this.cleanUpChildren(node);
18854 function cleanAttr(n,v)
18857 if (v.match(/^\./) || v.match(/^\//)) {
18860 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18863 if (v.match(/^#/)) {
18866 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18867 node.removeAttribute(n);
18871 var cwhite = this.cwhite;
18872 var cblack = this.cblack;
18874 function cleanStyle(n,v)
18876 if (v.match(/expression/)) { //XSS?? should we even bother..
18877 node.removeAttribute(n);
18881 var parts = v.split(/;/);
18884 Roo.each(parts, function(p) {
18885 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18889 var l = p.split(':').shift().replace(/\s+/g,'');
18890 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18892 if ( cwhite.length && cblack.indexOf(l) > -1) {
18893 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18894 //node.removeAttribute(n);
18898 // only allow 'c whitelisted system attributes'
18899 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18900 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18901 //node.removeAttribute(n);
18911 if (clean.length) {
18912 node.setAttribute(n, clean.join(';'));
18914 node.removeAttribute(n);
18920 for (var i = node.attributes.length-1; i > -1 ; i--) {
18921 var a = node.attributes[i];
18924 if (a.name.toLowerCase().substr(0,2)=='on') {
18925 node.removeAttribute(a.name);
18928 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18929 node.removeAttribute(a.name);
18932 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18933 cleanAttr(a.name,a.value); // fixme..
18936 if (a.name == 'style') {
18937 cleanStyle(a.name,a.value);
18940 /// clean up MS crap..
18941 // tecnically this should be a list of valid class'es..
18944 if (a.name == 'class') {
18945 if (a.value.match(/^Mso/)) {
18946 node.className = '';
18949 if (a.value.match(/body/)) {
18950 node.className = '';
18961 this.cleanUpChildren(node);
18966 * Clean up MS wordisms...
18968 cleanWord : function(node)
18971 var cleanWordChildren = function()
18973 if (!node.childNodes.length) {
18976 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18977 _t.cleanWord(node.childNodes[i]);
18983 this.cleanWord(this.doc.body);
18986 if (node.nodeName == "#text") {
18987 // clean up silly Windows -- stuff?
18990 if (node.nodeName == "#comment") {
18991 node.parentNode.removeChild(node);
18992 // clean up silly Windows -- stuff?
18996 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18997 node.parentNode.removeChild(node);
19001 // remove - but keep children..
19002 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19003 while (node.childNodes.length) {
19004 var cn = node.childNodes[0];
19005 node.removeChild(cn);
19006 node.parentNode.insertBefore(cn, node);
19008 node.parentNode.removeChild(node);
19009 cleanWordChildren();
19013 if (node.className.length) {
19015 var cn = node.className.split(/\W+/);
19017 Roo.each(cn, function(cls) {
19018 if (cls.match(/Mso[a-zA-Z]+/)) {
19023 node.className = cna.length ? cna.join(' ') : '';
19025 node.removeAttribute("class");
19029 if (node.hasAttribute("lang")) {
19030 node.removeAttribute("lang");
19033 if (node.hasAttribute("style")) {
19035 var styles = node.getAttribute("style").split(";");
19037 Roo.each(styles, function(s) {
19038 if (!s.match(/:/)) {
19041 var kv = s.split(":");
19042 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19045 // what ever is left... we allow.
19048 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19049 if (!nstyle.length) {
19050 node.removeAttribute('style');
19054 cleanWordChildren();
19058 domToHTML : function(currentElement, depth, nopadtext) {
19060 depth = depth || 0;
19061 nopadtext = nopadtext || false;
19063 if (!currentElement) {
19064 return this.domToHTML(this.doc.body);
19067 //Roo.log(currentElement);
19069 var allText = false;
19070 var nodeName = currentElement.nodeName;
19071 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19073 if (nodeName == '#text') {
19075 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19080 if (nodeName != 'BODY') {
19083 // Prints the node tagName, such as <A>, <IMG>, etc
19086 for(i = 0; i < currentElement.attributes.length;i++) {
19088 var aname = currentElement.attributes.item(i).name;
19089 if (!currentElement.attributes.item(i).value.length) {
19092 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19095 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19104 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19107 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19112 // Traverse the tree
19114 var currentElementChild = currentElement.childNodes.item(i);
19115 var allText = true;
19116 var innerHTML = '';
19118 while (currentElementChild) {
19119 // Formatting code (indent the tree so it looks nice on the screen)
19120 var nopad = nopadtext;
19121 if (lastnode == 'SPAN') {
19125 if (currentElementChild.nodeName == '#text') {
19126 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19127 toadd = nopadtext ? toadd : toadd.trim();
19128 if (!nopad && toadd.length > 80) {
19129 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19131 innerHTML += toadd;
19134 currentElementChild = currentElement.childNodes.item(i);
19140 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19142 // Recursively traverse the tree structure of the child node
19143 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19144 lastnode = currentElementChild.nodeName;
19146 currentElementChild=currentElement.childNodes.item(i);
19152 // The remaining code is mostly for formatting the tree
19153 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19158 ret+= "</"+tagName+">";
19164 applyBlacklists : function()
19166 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19167 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19171 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19172 if (b.indexOf(tag) > -1) {
19175 this.white.push(tag);
19179 Roo.each(w, function(tag) {
19180 if (b.indexOf(tag) > -1) {
19183 if (this.white.indexOf(tag) > -1) {
19186 this.white.push(tag);
19191 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19192 if (w.indexOf(tag) > -1) {
19195 this.black.push(tag);
19199 Roo.each(b, function(tag) {
19200 if (w.indexOf(tag) > -1) {
19203 if (this.black.indexOf(tag) > -1) {
19206 this.black.push(tag);
19211 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19212 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19216 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19217 if (b.indexOf(tag) > -1) {
19220 this.cwhite.push(tag);
19224 Roo.each(w, function(tag) {
19225 if (b.indexOf(tag) > -1) {
19228 if (this.cwhite.indexOf(tag) > -1) {
19231 this.cwhite.push(tag);
19236 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19237 if (w.indexOf(tag) > -1) {
19240 this.cblack.push(tag);
19244 Roo.each(b, function(tag) {
19245 if (w.indexOf(tag) > -1) {
19248 if (this.cblack.indexOf(tag) > -1) {
19251 this.cblack.push(tag);
19256 setStylesheets : function(stylesheets)
19258 if(typeof(stylesheets) == 'string'){
19259 Roo.get(this.iframe.contentDocument.head).createChild({
19261 rel : 'stylesheet',
19270 Roo.each(stylesheets, function(s) {
19275 Roo.get(_this.iframe.contentDocument.head).createChild({
19277 rel : 'stylesheet',
19286 removeStylesheets : function()
19290 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19295 // hide stuff that is not compatible
19309 * @event specialkey
19313 * @cfg {String} fieldClass @hide
19316 * @cfg {String} focusClass @hide
19319 * @cfg {String} autoCreate @hide
19322 * @cfg {String} inputType @hide
19325 * @cfg {String} invalidClass @hide
19328 * @cfg {String} invalidText @hide
19331 * @cfg {String} msgFx @hide
19334 * @cfg {String} validateOnBlur @hide
19338 Roo.HtmlEditorCore.white = [
19339 'area', 'br', 'img', 'input', 'hr', 'wbr',
19341 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19342 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19343 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19344 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19345 'table', 'ul', 'xmp',
19347 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19350 'dir', 'menu', 'ol', 'ul', 'dl',
19356 Roo.HtmlEditorCore.black = [
19357 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19359 'base', 'basefont', 'bgsound', 'blink', 'body',
19360 'frame', 'frameset', 'head', 'html', 'ilayer',
19361 'iframe', 'layer', 'link', 'meta', 'object',
19362 'script', 'style' ,'title', 'xml' // clean later..
19364 Roo.HtmlEditorCore.clean = [
19365 'script', 'style', 'title', 'xml'
19367 Roo.HtmlEditorCore.remove = [
19372 Roo.HtmlEditorCore.ablack = [
19376 Roo.HtmlEditorCore.aclean = [
19377 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19381 Roo.HtmlEditorCore.pwhite= [
19382 'http', 'https', 'mailto'
19385 // white listed style attributes.
19386 Roo.HtmlEditorCore.cwhite= [
19387 // 'text-align', /// default is to allow most things..
19393 // black listed style attributes.
19394 Roo.HtmlEditorCore.cblack= [
19395 // 'font-size' -- this can be set by the project
19399 Roo.HtmlEditorCore.swapCodes =[
19418 * @class Roo.bootstrap.HtmlEditor
19419 * @extends Roo.bootstrap.TextArea
19420 * Bootstrap HtmlEditor class
19423 * Create a new HtmlEditor
19424 * @param {Object} config The config object
19427 Roo.bootstrap.HtmlEditor = function(config){
19428 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19429 if (!this.toolbars) {
19430 this.toolbars = [];
19432 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19435 * @event initialize
19436 * Fires when the editor is fully initialized (including the iframe)
19437 * @param {HtmlEditor} this
19442 * Fires when the editor is first receives the focus. Any insertion must wait
19443 * until after this event.
19444 * @param {HtmlEditor} this
19448 * @event beforesync
19449 * Fires before the textarea is updated with content from the editor iframe. Return false
19450 * to cancel the sync.
19451 * @param {HtmlEditor} this
19452 * @param {String} html
19456 * @event beforepush
19457 * Fires before the iframe editor is updated with content from the textarea. Return false
19458 * to cancel the push.
19459 * @param {HtmlEditor} this
19460 * @param {String} html
19465 * Fires when the textarea is updated with content from the editor iframe.
19466 * @param {HtmlEditor} this
19467 * @param {String} html
19472 * Fires when the iframe editor is updated with content from the textarea.
19473 * @param {HtmlEditor} this
19474 * @param {String} html
19478 * @event editmodechange
19479 * Fires when the editor switches edit modes
19480 * @param {HtmlEditor} this
19481 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19483 editmodechange: true,
19485 * @event editorevent
19486 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19487 * @param {HtmlEditor} this
19491 * @event firstfocus
19492 * Fires when on first focus - needed by toolbars..
19493 * @param {HtmlEditor} this
19498 * Auto save the htmlEditor value as a file into Events
19499 * @param {HtmlEditor} this
19503 * @event savedpreview
19504 * preview the saved version of htmlEditor
19505 * @param {HtmlEditor} this
19512 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19516 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19521 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19526 * @cfg {Number} height (in pixels)
19530 * @cfg {Number} width (in pixels)
19535 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19538 stylesheets: false,
19543 // private properties
19544 validationEvent : false,
19546 initialized : false,
19549 onFocus : Roo.emptyFn,
19551 hideMode:'offsets',
19554 tbContainer : false,
19556 toolbarContainer :function() {
19557 return this.wrap.select('.x-html-editor-tb',true).first();
19561 * Protected method that will not generally be called directly. It
19562 * is called when the editor creates its toolbar. Override this method if you need to
19563 * add custom toolbar buttons.
19564 * @param {HtmlEditor} editor
19566 createToolbar : function(){
19568 Roo.log("create toolbars");
19570 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19571 this.toolbars[0].render(this.toolbarContainer());
19575 // if (!editor.toolbars || !editor.toolbars.length) {
19576 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19579 // for (var i =0 ; i < editor.toolbars.length;i++) {
19580 // editor.toolbars[i] = Roo.factory(
19581 // typeof(editor.toolbars[i]) == 'string' ?
19582 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19583 // Roo.bootstrap.HtmlEditor);
19584 // editor.toolbars[i].init(editor);
19590 onRender : function(ct, position)
19592 // Roo.log("Call onRender: " + this.xtype);
19594 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19596 this.wrap = this.inputEl().wrap({
19597 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19600 this.editorcore.onRender(ct, position);
19602 if (this.resizable) {
19603 this.resizeEl = new Roo.Resizable(this.wrap, {
19607 minHeight : this.height,
19608 height: this.height,
19609 handles : this.resizable,
19612 resize : function(r, w, h) {
19613 _t.onResize(w,h); // -something
19619 this.createToolbar(this);
19622 if(!this.width && this.resizable){
19623 this.setSize(this.wrap.getSize());
19625 if (this.resizeEl) {
19626 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19627 // should trigger onReize..
19633 onResize : function(w, h)
19635 Roo.log('resize: ' +w + ',' + h );
19636 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19640 if(this.inputEl() ){
19641 if(typeof w == 'number'){
19642 var aw = w - this.wrap.getFrameWidth('lr');
19643 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19646 if(typeof h == 'number'){
19647 var tbh = -11; // fixme it needs to tool bar size!
19648 for (var i =0; i < this.toolbars.length;i++) {
19649 // fixme - ask toolbars for heights?
19650 tbh += this.toolbars[i].el.getHeight();
19651 //if (this.toolbars[i].footer) {
19652 // tbh += this.toolbars[i].footer.el.getHeight();
19660 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19661 ah -= 5; // knock a few pixes off for look..
19662 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19666 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19667 this.editorcore.onResize(ew,eh);
19672 * Toggles the editor between standard and source edit mode.
19673 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19675 toggleSourceEdit : function(sourceEditMode)
19677 this.editorcore.toggleSourceEdit(sourceEditMode);
19679 if(this.editorcore.sourceEditMode){
19680 Roo.log('editor - showing textarea');
19683 // Roo.log(this.syncValue());
19685 this.inputEl().removeClass(['hide', 'x-hidden']);
19686 this.inputEl().dom.removeAttribute('tabIndex');
19687 this.inputEl().focus();
19689 Roo.log('editor - hiding textarea');
19691 // Roo.log(this.pushValue());
19694 this.inputEl().addClass(['hide', 'x-hidden']);
19695 this.inputEl().dom.setAttribute('tabIndex', -1);
19696 //this.deferFocus();
19699 if(this.resizable){
19700 this.setSize(this.wrap.getSize());
19703 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19706 // private (for BoxComponent)
19707 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19709 // private (for BoxComponent)
19710 getResizeEl : function(){
19714 // private (for BoxComponent)
19715 getPositionEl : function(){
19720 initEvents : function(){
19721 this.originalValue = this.getValue();
19725 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19728 // markInvalid : Roo.emptyFn,
19730 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19733 // clearInvalid : Roo.emptyFn,
19735 setValue : function(v){
19736 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19737 this.editorcore.pushValue();
19742 deferFocus : function(){
19743 this.focus.defer(10, this);
19747 focus : function(){
19748 this.editorcore.focus();
19754 onDestroy : function(){
19760 for (var i =0; i < this.toolbars.length;i++) {
19761 // fixme - ask toolbars for heights?
19762 this.toolbars[i].onDestroy();
19765 this.wrap.dom.innerHTML = '';
19766 this.wrap.remove();
19771 onFirstFocus : function(){
19772 //Roo.log("onFirstFocus");
19773 this.editorcore.onFirstFocus();
19774 for (var i =0; i < this.toolbars.length;i++) {
19775 this.toolbars[i].onFirstFocus();
19781 syncValue : function()
19783 this.editorcore.syncValue();
19786 pushValue : function()
19788 this.editorcore.pushValue();
19792 // hide stuff that is not compatible
19806 * @event specialkey
19810 * @cfg {String} fieldClass @hide
19813 * @cfg {String} focusClass @hide
19816 * @cfg {String} autoCreate @hide
19819 * @cfg {String} inputType @hide
19822 * @cfg {String} invalidClass @hide
19825 * @cfg {String} invalidText @hide
19828 * @cfg {String} msgFx @hide
19831 * @cfg {String} validateOnBlur @hide
19840 Roo.namespace('Roo.bootstrap.htmleditor');
19842 * @class Roo.bootstrap.HtmlEditorToolbar1
19847 new Roo.bootstrap.HtmlEditor({
19850 new Roo.bootstrap.HtmlEditorToolbar1({
19851 disable : { fonts: 1 , format: 1, ..., ... , ...],
19857 * @cfg {Object} disable List of elements to disable..
19858 * @cfg {Array} btns List of additional buttons.
19862 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19865 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19868 Roo.apply(this, config);
19870 // default disabled, based on 'good practice'..
19871 this.disable = this.disable || {};
19872 Roo.applyIf(this.disable, {
19875 specialElements : true
19877 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19879 this.editor = config.editor;
19880 this.editorcore = config.editor.editorcore;
19882 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19884 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19885 // dont call parent... till later.
19887 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19892 editorcore : false,
19897 "h1","h2","h3","h4","h5","h6",
19899 "abbr", "acronym", "address", "cite", "samp", "var",
19903 onRender : function(ct, position)
19905 // Roo.log("Call onRender: " + this.xtype);
19907 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19909 this.el.dom.style.marginBottom = '0';
19911 var editorcore = this.editorcore;
19912 var editor= this.editor;
19915 var btn = function(id,cmd , toggle, handler){
19917 var event = toggle ? 'toggle' : 'click';
19922 xns: Roo.bootstrap,
19925 enableToggle:toggle !== false,
19927 pressed : toggle ? false : null,
19930 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19931 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19940 xns: Roo.bootstrap,
19941 glyphicon : 'font',
19945 xns: Roo.bootstrap,
19949 Roo.each(this.formats, function(f) {
19950 style.menu.items.push({
19952 xns: Roo.bootstrap,
19953 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19958 editorcore.insertTag(this.tagname);
19965 children.push(style);
19968 btn('bold',false,true);
19969 btn('italic',false,true);
19970 btn('align-left', 'justifyleft',true);
19971 btn('align-center', 'justifycenter',true);
19972 btn('align-right' , 'justifyright',true);
19973 btn('link', false, false, function(btn) {
19974 //Roo.log("create link?");
19975 var url = prompt(this.createLinkText, this.defaultLinkValue);
19976 if(url && url != 'http:/'+'/'){
19977 this.editorcore.relayCmd('createlink', url);
19980 btn('list','insertunorderedlist',true);
19981 btn('pencil', false,true, function(btn){
19984 this.toggleSourceEdit(btn.pressed);
19990 xns: Roo.bootstrap,
19995 xns: Roo.bootstrap,
20000 cog.menu.items.push({
20002 xns: Roo.bootstrap,
20003 html : Clean styles,
20008 editorcore.insertTag(this.tagname);
20017 this.xtype = 'NavSimplebar';
20019 for(var i=0;i< children.length;i++) {
20021 this.buttons.add(this.addxtypeChild(children[i]));
20025 editor.on('editorevent', this.updateToolbar, this);
20027 onBtnClick : function(id)
20029 this.editorcore.relayCmd(id);
20030 this.editorcore.focus();
20034 * Protected method that will not generally be called directly. It triggers
20035 * a toolbar update by reading the markup state of the current selection in the editor.
20037 updateToolbar: function(){
20039 if(!this.editorcore.activated){
20040 this.editor.onFirstFocus(); // is this neeed?
20044 var btns = this.buttons;
20045 var doc = this.editorcore.doc;
20046 btns.get('bold').setActive(doc.queryCommandState('bold'));
20047 btns.get('italic').setActive(doc.queryCommandState('italic'));
20048 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20050 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20051 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20052 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20054 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20055 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20058 var ans = this.editorcore.getAllAncestors();
20059 if (this.formatCombo) {
20062 var store = this.formatCombo.store;
20063 this.formatCombo.setValue("");
20064 for (var i =0; i < ans.length;i++) {
20065 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20067 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20075 // hides menus... - so this cant be on a menu...
20076 Roo.bootstrap.MenuMgr.hideAll();
20078 Roo.bootstrap.MenuMgr.hideAll();
20079 //this.editorsyncValue();
20081 onFirstFocus: function() {
20082 this.buttons.each(function(item){
20086 toggleSourceEdit : function(sourceEditMode){
20089 if(sourceEditMode){
20090 Roo.log("disabling buttons");
20091 this.buttons.each( function(item){
20092 if(item.cmd != 'pencil'){
20098 Roo.log("enabling buttons");
20099 if(this.editorcore.initialized){
20100 this.buttons.each( function(item){
20106 Roo.log("calling toggole on editor");
20107 // tell the editor that it's been pressed..
20108 this.editor.toggleSourceEdit(sourceEditMode);
20118 * @class Roo.bootstrap.Table.AbstractSelectionModel
20119 * @extends Roo.util.Observable
20120 * Abstract base class for grid SelectionModels. It provides the interface that should be
20121 * implemented by descendant classes. This class should not be directly instantiated.
20124 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20125 this.locked = false;
20126 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20130 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20131 /** @ignore Called by the grid automatically. Do not call directly. */
20132 init : function(grid){
20138 * Locks the selections.
20141 this.locked = true;
20145 * Unlocks the selections.
20147 unlock : function(){
20148 this.locked = false;
20152 * Returns true if the selections are locked.
20153 * @return {Boolean}
20155 isLocked : function(){
20156 return this.locked;
20160 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20161 * @class Roo.bootstrap.Table.RowSelectionModel
20162 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20163 * It supports multiple selections and keyboard selection/navigation.
20165 * @param {Object} config
20168 Roo.bootstrap.Table.RowSelectionModel = function(config){
20169 Roo.apply(this, config);
20170 this.selections = new Roo.util.MixedCollection(false, function(o){
20175 this.lastActive = false;
20179 * @event selectionchange
20180 * Fires when the selection changes
20181 * @param {SelectionModel} this
20183 "selectionchange" : true,
20185 * @event afterselectionchange
20186 * Fires after the selection changes (eg. by key press or clicking)
20187 * @param {SelectionModel} this
20189 "afterselectionchange" : true,
20191 * @event beforerowselect
20192 * Fires when a row is selected being selected, return false to cancel.
20193 * @param {SelectionModel} this
20194 * @param {Number} rowIndex The selected index
20195 * @param {Boolean} keepExisting False if other selections will be cleared
20197 "beforerowselect" : true,
20200 * Fires when a row is selected.
20201 * @param {SelectionModel} this
20202 * @param {Number} rowIndex The selected index
20203 * @param {Roo.data.Record} r The record
20205 "rowselect" : true,
20207 * @event rowdeselect
20208 * Fires when a row is deselected.
20209 * @param {SelectionModel} this
20210 * @param {Number} rowIndex The selected index
20212 "rowdeselect" : true
20214 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20215 this.locked = false;
20218 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20220 * @cfg {Boolean} singleSelect
20221 * True to allow selection of only one row at a time (defaults to false)
20223 singleSelect : false,
20226 initEvents : function(){
20228 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20229 this.grid.on("mousedown", this.handleMouseDown, this);
20230 }else{ // allow click to work like normal
20231 this.grid.on("rowclick", this.handleDragableRowClick, this);
20234 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20235 "up" : function(e){
20237 this.selectPrevious(e.shiftKey);
20238 }else if(this.last !== false && this.lastActive !== false){
20239 var last = this.last;
20240 this.selectRange(this.last, this.lastActive-1);
20241 this.grid.getView().focusRow(this.lastActive);
20242 if(last !== false){
20246 this.selectFirstRow();
20248 this.fireEvent("afterselectionchange", this);
20250 "down" : function(e){
20252 this.selectNext(e.shiftKey);
20253 }else if(this.last !== false && this.lastActive !== false){
20254 var last = this.last;
20255 this.selectRange(this.last, this.lastActive+1);
20256 this.grid.getView().focusRow(this.lastActive);
20257 if(last !== false){
20261 this.selectFirstRow();
20263 this.fireEvent("afterselectionchange", this);
20268 var view = this.grid.view;
20269 view.on("refresh", this.onRefresh, this);
20270 view.on("rowupdated", this.onRowUpdated, this);
20271 view.on("rowremoved", this.onRemove, this);
20275 onRefresh : function(){
20276 var ds = this.grid.dataSource, i, v = this.grid.view;
20277 var s = this.selections;
20278 s.each(function(r){
20279 if((i = ds.indexOfId(r.id)) != -1){
20288 onRemove : function(v, index, r){
20289 this.selections.remove(r);
20293 onRowUpdated : function(v, index, r){
20294 if(this.isSelected(r)){
20295 v.onRowSelect(index);
20301 * @param {Array} records The records to select
20302 * @param {Boolean} keepExisting (optional) True to keep existing selections
20304 selectRecords : function(records, keepExisting){
20306 this.clearSelections();
20308 var ds = this.grid.dataSource;
20309 for(var i = 0, len = records.length; i < len; i++){
20310 this.selectRow(ds.indexOf(records[i]), true);
20315 * Gets the number of selected rows.
20318 getCount : function(){
20319 return this.selections.length;
20323 * Selects the first row in the grid.
20325 selectFirstRow : function(){
20330 * Select the last row.
20331 * @param {Boolean} keepExisting (optional) True to keep existing selections
20333 selectLastRow : function(keepExisting){
20334 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20338 * Selects the row immediately following the last selected row.
20339 * @param {Boolean} keepExisting (optional) True to keep existing selections
20341 selectNext : function(keepExisting){
20342 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20343 this.selectRow(this.last+1, keepExisting);
20344 this.grid.getView().focusRow(this.last);
20349 * Selects the row that precedes the last selected row.
20350 * @param {Boolean} keepExisting (optional) True to keep existing selections
20352 selectPrevious : function(keepExisting){
20354 this.selectRow(this.last-1, keepExisting);
20355 this.grid.getView().focusRow(this.last);
20360 * Returns the selected records
20361 * @return {Array} Array of selected records
20363 getSelections : function(){
20364 return [].concat(this.selections.items);
20368 * Returns the first selected record.
20371 getSelected : function(){
20372 return this.selections.itemAt(0);
20377 * Clears all selections.
20379 clearSelections : function(fast){
20380 if(this.locked) return;
20382 var ds = this.grid.dataSource;
20383 var s = this.selections;
20384 s.each(function(r){
20385 this.deselectRow(ds.indexOfId(r.id));
20389 this.selections.clear();
20396 * Selects all rows.
20398 selectAll : function(){
20399 if(this.locked) return;
20400 this.selections.clear();
20401 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20402 this.selectRow(i, true);
20407 * Returns True if there is a selection.
20408 * @return {Boolean}
20410 hasSelection : function(){
20411 return this.selections.length > 0;
20415 * Returns True if the specified row is selected.
20416 * @param {Number/Record} record The record or index of the record to check
20417 * @return {Boolean}
20419 isSelected : function(index){
20420 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20421 return (r && this.selections.key(r.id) ? true : false);
20425 * Returns True if the specified record id is selected.
20426 * @param {String} id The id of record to check
20427 * @return {Boolean}
20429 isIdSelected : function(id){
20430 return (this.selections.key(id) ? true : false);
20434 handleMouseDown : function(e, t){
20435 var view = this.grid.getView(), rowIndex;
20436 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20439 if(e.shiftKey && this.last !== false){
20440 var last = this.last;
20441 this.selectRange(last, rowIndex, e.ctrlKey);
20442 this.last = last; // reset the last
20443 view.focusRow(rowIndex);
20445 var isSelected = this.isSelected(rowIndex);
20446 if(e.button !== 0 && isSelected){
20447 view.focusRow(rowIndex);
20448 }else if(e.ctrlKey && isSelected){
20449 this.deselectRow(rowIndex);
20450 }else if(!isSelected){
20451 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20452 view.focusRow(rowIndex);
20455 this.fireEvent("afterselectionchange", this);
20458 handleDragableRowClick : function(grid, rowIndex, e)
20460 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20461 this.selectRow(rowIndex, false);
20462 grid.view.focusRow(rowIndex);
20463 this.fireEvent("afterselectionchange", this);
20468 * Selects multiple rows.
20469 * @param {Array} rows Array of the indexes of the row to select
20470 * @param {Boolean} keepExisting (optional) True to keep existing selections
20472 selectRows : function(rows, keepExisting){
20474 this.clearSelections();
20476 for(var i = 0, len = rows.length; i < len; i++){
20477 this.selectRow(rows[i], true);
20482 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20483 * @param {Number} startRow The index of the first row in the range
20484 * @param {Number} endRow The index of the last row in the range
20485 * @param {Boolean} keepExisting (optional) True to retain existing selections
20487 selectRange : function(startRow, endRow, keepExisting){
20488 if(this.locked) return;
20490 this.clearSelections();
20492 if(startRow <= endRow){
20493 for(var i = startRow; i <= endRow; i++){
20494 this.selectRow(i, true);
20497 for(var i = startRow; i >= endRow; i--){
20498 this.selectRow(i, true);
20504 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20505 * @param {Number} startRow The index of the first row in the range
20506 * @param {Number} endRow The index of the last row in the range
20508 deselectRange : function(startRow, endRow, preventViewNotify){
20509 if(this.locked) return;
20510 for(var i = startRow; i <= endRow; i++){
20511 this.deselectRow(i, preventViewNotify);
20517 * @param {Number} row The index of the row to select
20518 * @param {Boolean} keepExisting (optional) True to keep existing selections
20520 selectRow : function(index, keepExisting, preventViewNotify){
20521 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20522 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20523 if(!keepExisting || this.singleSelect){
20524 this.clearSelections();
20526 var r = this.grid.dataSource.getAt(index);
20527 this.selections.add(r);
20528 this.last = this.lastActive = index;
20529 if(!preventViewNotify){
20530 this.grid.getView().onRowSelect(index);
20532 this.fireEvent("rowselect", this, index, r);
20533 this.fireEvent("selectionchange", this);
20539 * @param {Number} row The index of the row to deselect
20541 deselectRow : function(index, preventViewNotify){
20542 if(this.locked) return;
20543 if(this.last == index){
20546 if(this.lastActive == index){
20547 this.lastActive = false;
20549 var r = this.grid.dataSource.getAt(index);
20550 this.selections.remove(r);
20551 if(!preventViewNotify){
20552 this.grid.getView().onRowDeselect(index);
20554 this.fireEvent("rowdeselect", this, index);
20555 this.fireEvent("selectionchange", this);
20559 restoreLast : function(){
20561 this.last = this._last;
20566 acceptsNav : function(row, col, cm){
20567 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20571 onEditorKey : function(field, e){
20572 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20577 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20579 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20581 }else if(k == e.ENTER && !e.ctrlKey){
20585 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20587 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20589 }else if(k == e.ESC){
20593 g.startEditing(newCell[0], newCell[1]);
20598 * Ext JS Library 1.1.1
20599 * Copyright(c) 2006-2007, Ext JS, LLC.
20601 * Originally Released Under LGPL - original licence link has changed is not relivant.
20604 * <script type="text/javascript">
20608 * @class Roo.bootstrap.PagingToolbar
20610 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20612 * Create a new PagingToolbar
20613 * @param {Object} config The config object
20615 Roo.bootstrap.PagingToolbar = function(config)
20617 // old args format still supported... - xtype is prefered..
20618 // created from xtype...
20619 var ds = config.dataSource;
20620 this.toolbarItems = [];
20621 if (config.items) {
20622 this.toolbarItems = config.items;
20623 // config.items = [];
20626 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20633 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20637 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20639 * @cfg {Roo.data.Store} dataSource
20640 * The underlying data store providing the paged data
20643 * @cfg {String/HTMLElement/Element} container
20644 * container The id or element that will contain the toolbar
20647 * @cfg {Boolean} displayInfo
20648 * True to display the displayMsg (defaults to false)
20651 * @cfg {Number} pageSize
20652 * The number of records to display per page (defaults to 20)
20656 * @cfg {String} displayMsg
20657 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20659 displayMsg : 'Displaying {0} - {1} of {2}',
20661 * @cfg {String} emptyMsg
20662 * The message to display when no records are found (defaults to "No data to display")
20664 emptyMsg : 'No data to display',
20666 * Customizable piece of the default paging text (defaults to "Page")
20669 beforePageText : "Page",
20671 * Customizable piece of the default paging text (defaults to "of %0")
20674 afterPageText : "of {0}",
20676 * Customizable piece of the default paging text (defaults to "First Page")
20679 firstText : "First Page",
20681 * Customizable piece of the default paging text (defaults to "Previous Page")
20684 prevText : "Previous Page",
20686 * Customizable piece of the default paging text (defaults to "Next Page")
20689 nextText : "Next Page",
20691 * Customizable piece of the default paging text (defaults to "Last Page")
20694 lastText : "Last Page",
20696 * Customizable piece of the default paging text (defaults to "Refresh")
20699 refreshText : "Refresh",
20703 onRender : function(ct, position)
20705 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20706 this.navgroup.parentId = this.id;
20707 this.navgroup.onRender(this.el, null);
20708 // add the buttons to the navgroup
20710 if(this.displayInfo){
20711 Roo.log(this.el.select('ul.navbar-nav',true).first());
20712 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20713 this.displayEl = this.el.select('.x-paging-info', true).first();
20714 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20715 // this.displayEl = navel.el.select('span',true).first();
20721 Roo.each(_this.buttons, function(e){
20722 Roo.factory(e).onRender(_this.el, null);
20726 Roo.each(_this.toolbarItems, function(e) {
20727 _this.navgroup.addItem(e);
20731 this.first = this.navgroup.addItem({
20732 tooltip: this.firstText,
20734 icon : 'fa fa-backward',
20736 preventDefault: true,
20737 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20740 this.prev = this.navgroup.addItem({
20741 tooltip: this.prevText,
20743 icon : 'fa fa-step-backward',
20745 preventDefault: true,
20746 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20748 //this.addSeparator();
20751 var field = this.navgroup.addItem( {
20753 cls : 'x-paging-position',
20755 html : this.beforePageText +
20756 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20757 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20760 this.field = field.el.select('input', true).first();
20761 this.field.on("keydown", this.onPagingKeydown, this);
20762 this.field.on("focus", function(){this.dom.select();});
20765 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20766 //this.field.setHeight(18);
20767 //this.addSeparator();
20768 this.next = this.navgroup.addItem({
20769 tooltip: this.nextText,
20771 html : ' <i class="fa fa-step-forward">',
20773 preventDefault: true,
20774 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20776 this.last = this.navgroup.addItem({
20777 tooltip: this.lastText,
20778 icon : 'fa fa-forward',
20781 preventDefault: true,
20782 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20784 //this.addSeparator();
20785 this.loading = this.navgroup.addItem({
20786 tooltip: this.refreshText,
20787 icon: 'fa fa-refresh',
20788 preventDefault: true,
20789 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20795 updateInfo : function(){
20796 if(this.displayEl){
20797 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20798 var msg = count == 0 ?
20802 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20804 this.displayEl.update(msg);
20809 onLoad : function(ds, r, o){
20810 this.cursor = o.params ? o.params.start : 0;
20811 var d = this.getPageData(),
20815 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20816 this.field.dom.value = ap;
20817 this.first.setDisabled(ap == 1);
20818 this.prev.setDisabled(ap == 1);
20819 this.next.setDisabled(ap == ps);
20820 this.last.setDisabled(ap == ps);
20821 this.loading.enable();
20826 getPageData : function(){
20827 var total = this.ds.getTotalCount();
20830 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20831 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20836 onLoadError : function(){
20837 this.loading.enable();
20841 onPagingKeydown : function(e){
20842 var k = e.getKey();
20843 var d = this.getPageData();
20845 var v = this.field.dom.value, pageNum;
20846 if(!v || isNaN(pageNum = parseInt(v, 10))){
20847 this.field.dom.value = d.activePage;
20850 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20851 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20854 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
20856 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20857 this.field.dom.value = pageNum;
20858 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20861 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20863 var v = this.field.dom.value, pageNum;
20864 var increment = (e.shiftKey) ? 10 : 1;
20865 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20867 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20868 this.field.dom.value = d.activePage;
20871 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20873 this.field.dom.value = parseInt(v, 10) + increment;
20874 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20875 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20882 beforeLoad : function(){
20884 this.loading.disable();
20889 onClick : function(which){
20898 ds.load({params:{start: 0, limit: this.pageSize}});
20901 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20904 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20907 var total = ds.getTotalCount();
20908 var extra = total % this.pageSize;
20909 var lastStart = extra ? (total - extra) : total-this.pageSize;
20910 ds.load({params:{start: lastStart, limit: this.pageSize}});
20913 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20919 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20920 * @param {Roo.data.Store} store The data store to unbind
20922 unbind : function(ds){
20923 ds.un("beforeload", this.beforeLoad, this);
20924 ds.un("load", this.onLoad, this);
20925 ds.un("loadexception", this.onLoadError, this);
20926 ds.un("remove", this.updateInfo, this);
20927 ds.un("add", this.updateInfo, this);
20928 this.ds = undefined;
20932 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20933 * @param {Roo.data.Store} store The data store to bind
20935 bind : function(ds){
20936 ds.on("beforeload", this.beforeLoad, this);
20937 ds.on("load", this.onLoad, this);
20938 ds.on("loadexception", this.onLoadError, this);
20939 ds.on("remove", this.updateInfo, this);
20940 ds.on("add", this.updateInfo, this);
20951 * @class Roo.bootstrap.MessageBar
20952 * @extends Roo.bootstrap.Component
20953 * Bootstrap MessageBar class
20954 * @cfg {String} html contents of the MessageBar
20955 * @cfg {String} weight (info | success | warning | danger) default info
20956 * @cfg {String} beforeClass insert the bar before the given class
20957 * @cfg {Boolean} closable (true | false) default false
20958 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20961 * Create a new Element
20962 * @param {Object} config The config object
20965 Roo.bootstrap.MessageBar = function(config){
20966 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20969 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20975 beforeClass: 'bootstrap-sticky-wrap',
20977 getAutoCreate : function(){
20981 cls: 'alert alert-dismissable alert-' + this.weight,
20986 html: this.html || ''
20992 cfg.cls += ' alert-messages-fixed';
21006 onRender : function(ct, position)
21008 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21011 var cfg = Roo.apply({}, this.getAutoCreate());
21015 cfg.cls += ' ' + this.cls;
21018 cfg.style = this.style;
21020 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21022 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21025 this.el.select('>button.close').on('click', this.hide, this);
21031 if (!this.rendered) {
21037 this.fireEvent('show', this);
21043 if (!this.rendered) {
21049 this.fireEvent('hide', this);
21052 update : function()
21054 // var e = this.el.dom.firstChild;
21056 // if(this.closable){
21057 // e = e.nextSibling;
21060 // e.data = this.html || '';
21062 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21078 * @class Roo.bootstrap.Graph
21079 * @extends Roo.bootstrap.Component
21080 * Bootstrap Graph class
21084 @cfg {String} graphtype bar | vbar | pie
21085 @cfg {number} g_x coodinator | centre x (pie)
21086 @cfg {number} g_y coodinator | centre y (pie)
21087 @cfg {number} g_r radius (pie)
21088 @cfg {number} g_height height of the chart (respected by all elements in the set)
21089 @cfg {number} g_width width of the chart (respected by all elements in the set)
21090 @cfg {Object} title The title of the chart
21093 -opts (object) options for the chart
21095 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21096 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21098 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
21099 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21101 o stretch (boolean)
21103 -opts (object) options for the pie
21106 o startAngle (number)
21107 o endAngle (number)
21111 * Create a new Input
21112 * @param {Object} config The config object
21115 Roo.bootstrap.Graph = function(config){
21116 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21122 * The img click event for the img.
21123 * @param {Roo.EventObject} e
21129 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21140 //g_colors: this.colors,
21147 getAutoCreate : function(){
21158 onRender : function(ct,position){
21159 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21160 this.raphael = Raphael(this.el.dom);
21162 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21163 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21164 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21165 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21167 r.text(160, 10, "Single Series Chart").attr(txtattr);
21168 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21169 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21170 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21172 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21173 r.barchart(330, 10, 300, 220, data1);
21174 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21175 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21178 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21179 // r.barchart(30, 30, 560, 250, xdata, {
21180 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21181 // axis : "0 0 1 1",
21182 // axisxlabels : xdata
21183 // //yvalues : cols,
21186 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21188 // this.load(null,xdata,{
21189 // axis : "0 0 1 1",
21190 // axisxlabels : xdata
21195 load : function(graphtype,xdata,opts){
21196 this.raphael.clear();
21198 graphtype = this.graphtype;
21203 var r = this.raphael,
21204 fin = function () {
21205 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21207 fout = function () {
21208 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21210 pfin = function() {
21211 this.sector.stop();
21212 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21215 this.label[0].stop();
21216 this.label[0].attr({ r: 7.5 });
21217 this.label[1].attr({ "font-weight": 800 });
21220 pfout = function() {
21221 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21224 this.label[0].animate({ r: 5 }, 500, "bounce");
21225 this.label[1].attr({ "font-weight": 400 });
21231 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21234 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21237 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21238 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21240 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21247 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21252 setTitle: function(o)
21257 initEvents: function() {
21260 this.el.on('click', this.onClick, this);
21264 onClick : function(e)
21266 Roo.log('img onclick');
21267 this.fireEvent('click', this, e);
21279 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21282 * @class Roo.bootstrap.dash.NumberBox
21283 * @extends Roo.bootstrap.Component
21284 * Bootstrap NumberBox class
21285 * @cfg {String} headline Box headline
21286 * @cfg {String} content Box content
21287 * @cfg {String} icon Box icon
21288 * @cfg {String} footer Footer text
21289 * @cfg {String} fhref Footer href
21292 * Create a new NumberBox
21293 * @param {Object} config The config object
21297 Roo.bootstrap.dash.NumberBox = function(config){
21298 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21302 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21311 getAutoCreate : function(){
21315 cls : 'small-box ',
21323 cls : 'roo-headline',
21324 html : this.headline
21328 cls : 'roo-content',
21329 html : this.content
21343 cls : 'ion ' + this.icon
21352 cls : 'small-box-footer',
21353 href : this.fhref || '#',
21357 cfg.cn.push(footer);
21364 onRender : function(ct,position){
21365 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21372 setHeadline: function (value)
21374 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21377 setFooter: function (value, href)
21379 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21382 this.el.select('a.small-box-footer',true).first().attr('href', href);
21387 setContent: function (value)
21389 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21392 initEvents: function()
21406 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21409 * @class Roo.bootstrap.dash.TabBox
21410 * @extends Roo.bootstrap.Component
21411 * Bootstrap TabBox class
21412 * @cfg {String} title Title of the TabBox
21413 * @cfg {String} icon Icon of the TabBox
21414 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21415 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21418 * Create a new TabBox
21419 * @param {Object} config The config object
21423 Roo.bootstrap.dash.TabBox = function(config){
21424 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21429 * When a pane is added
21430 * @param {Roo.bootstrap.dash.TabPane} pane
21434 * @event activatepane
21435 * When a pane is activated
21436 * @param {Roo.bootstrap.dash.TabPane} pane
21438 "activatepane" : true
21446 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21451 tabScrollable : false,
21453 getChildContainer : function()
21455 return this.el.select('.tab-content', true).first();
21458 getAutoCreate : function(){
21462 cls: 'pull-left header',
21470 cls: 'fa ' + this.icon
21476 cls: 'nav nav-tabs pull-right',
21482 if(this.tabScrollable){
21489 cls: 'nav nav-tabs pull-right',
21500 cls: 'nav-tabs-custom',
21505 cls: 'tab-content no-padding',
21513 initEvents : function()
21515 //Roo.log('add add pane handler');
21516 this.on('addpane', this.onAddPane, this);
21519 * Updates the box title
21520 * @param {String} html to set the title to.
21522 setTitle : function(value)
21524 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21526 onAddPane : function(pane)
21528 this.panes.push(pane);
21529 //Roo.log('addpane');
21531 // tabs are rendere left to right..
21532 if(!this.showtabs){
21536 var ctr = this.el.select('.nav-tabs', true).first();
21539 var existing = ctr.select('.nav-tab',true);
21540 var qty = existing.getCount();;
21543 var tab = ctr.createChild({
21545 cls : 'nav-tab' + (qty ? '' : ' active'),
21553 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21556 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21558 pane.el.addClass('active');
21563 onTabClick : function(ev,un,ob,pane)
21565 //Roo.log('tab - prev default');
21566 ev.preventDefault();
21569 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21570 pane.tab.addClass('active');
21571 //Roo.log(pane.title);
21572 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21573 // technically we should have a deactivate event.. but maybe add later.
21574 // and it should not de-activate the selected tab...
21575 this.fireEvent('activatepane', pane);
21576 pane.el.addClass('active');
21577 pane.fireEvent('activate');
21582 getActivePane : function()
21585 Roo.each(this.panes, function(p) {
21586 if(p.el.hasClass('active')){
21607 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21609 * @class Roo.bootstrap.TabPane
21610 * @extends Roo.bootstrap.Component
21611 * Bootstrap TabPane class
21612 * @cfg {Boolean} active (false | true) Default false
21613 * @cfg {String} title title of panel
21617 * Create a new TabPane
21618 * @param {Object} config The config object
21621 Roo.bootstrap.dash.TabPane = function(config){
21622 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21628 * When a pane is activated
21629 * @param {Roo.bootstrap.dash.TabPane} pane
21636 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21641 // the tabBox that this is attached to.
21644 getAutoCreate : function()
21652 cfg.cls += ' active';
21657 initEvents : function()
21659 //Roo.log('trigger add pane handler');
21660 this.parent().fireEvent('addpane', this)
21664 * Updates the tab title
21665 * @param {String} html to set the title to.
21667 setTitle: function(str)
21673 this.tab.select('a', true).first().dom.innerHTML = str;
21690 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21693 * @class Roo.bootstrap.menu.Menu
21694 * @extends Roo.bootstrap.Component
21695 * Bootstrap Menu class - container for Menu
21696 * @cfg {String} html Text of the menu
21697 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21698 * @cfg {String} icon Font awesome icon
21699 * @cfg {String} pos Menu align to (top | bottom) default bottom
21703 * Create a new Menu
21704 * @param {Object} config The config object
21708 Roo.bootstrap.menu.Menu = function(config){
21709 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21713 * @event beforeshow
21714 * Fires before this menu is displayed
21715 * @param {Roo.bootstrap.menu.Menu} this
21719 * @event beforehide
21720 * Fires before this menu is hidden
21721 * @param {Roo.bootstrap.menu.Menu} this
21726 * Fires after this menu is displayed
21727 * @param {Roo.bootstrap.menu.Menu} this
21732 * Fires after this menu is hidden
21733 * @param {Roo.bootstrap.menu.Menu} this
21738 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21739 * @param {Roo.bootstrap.menu.Menu} this
21740 * @param {Roo.EventObject} e
21747 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21751 weight : 'default',
21756 getChildContainer : function() {
21757 if(this.isSubMenu){
21761 return this.el.select('ul.dropdown-menu', true).first();
21764 getAutoCreate : function()
21769 cls : 'roo-menu-text',
21777 cls : 'fa ' + this.icon
21788 cls : 'dropdown-button btn btn-' + this.weight,
21793 cls : 'dropdown-toggle btn btn-' + this.weight,
21803 cls : 'dropdown-menu'
21809 if(this.pos == 'top'){
21810 cfg.cls += ' dropup';
21813 if(this.isSubMenu){
21816 cls : 'dropdown-menu'
21823 onRender : function(ct, position)
21825 this.isSubMenu = ct.hasClass('dropdown-submenu');
21827 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21830 initEvents : function()
21832 if(this.isSubMenu){
21836 this.hidden = true;
21838 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21839 this.triggerEl.on('click', this.onTriggerPress, this);
21841 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21842 this.buttonEl.on('click', this.onClick, this);
21848 if(this.isSubMenu){
21852 return this.el.select('ul.dropdown-menu', true).first();
21855 onClick : function(e)
21857 this.fireEvent("click", this, e);
21860 onTriggerPress : function(e)
21862 if (this.isVisible()) {
21869 isVisible : function(){
21870 return !this.hidden;
21875 this.fireEvent("beforeshow", this);
21877 this.hidden = false;
21878 this.el.addClass('open');
21880 Roo.get(document).on("mouseup", this.onMouseUp, this);
21882 this.fireEvent("show", this);
21889 this.fireEvent("beforehide", this);
21891 this.hidden = true;
21892 this.el.removeClass('open');
21894 Roo.get(document).un("mouseup", this.onMouseUp);
21896 this.fireEvent("hide", this);
21899 onMouseUp : function()
21913 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21916 * @class Roo.bootstrap.menu.Item
21917 * @extends Roo.bootstrap.Component
21918 * Bootstrap MenuItem class
21919 * @cfg {Boolean} submenu (true | false) default false
21920 * @cfg {String} html text of the item
21921 * @cfg {String} href the link
21922 * @cfg {Boolean} disable (true | false) default false
21923 * @cfg {Boolean} preventDefault (true | false) default true
21924 * @cfg {String} icon Font awesome icon
21925 * @cfg {String} pos Submenu align to (left | right) default right
21929 * Create a new Item
21930 * @param {Object} config The config object
21934 Roo.bootstrap.menu.Item = function(config){
21935 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21939 * Fires when the mouse is hovering over this menu
21940 * @param {Roo.bootstrap.menu.Item} this
21941 * @param {Roo.EventObject} e
21946 * Fires when the mouse exits this menu
21947 * @param {Roo.bootstrap.menu.Item} this
21948 * @param {Roo.EventObject} e
21954 * The raw click event for the entire grid.
21955 * @param {Roo.EventObject} e
21961 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21966 preventDefault: true,
21971 getAutoCreate : function()
21976 cls : 'roo-menu-item-text',
21984 cls : 'fa ' + this.icon
21993 href : this.href || '#',
22000 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22004 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22006 if(this.pos == 'left'){
22007 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22014 initEvents : function()
22016 this.el.on('mouseover', this.onMouseOver, this);
22017 this.el.on('mouseout', this.onMouseOut, this);
22019 this.el.select('a', true).first().on('click', this.onClick, this);
22023 onClick : function(e)
22025 if(this.preventDefault){
22026 e.preventDefault();
22029 this.fireEvent("click", this, e);
22032 onMouseOver : function(e)
22034 if(this.submenu && this.pos == 'left'){
22035 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22038 this.fireEvent("mouseover", this, e);
22041 onMouseOut : function(e)
22043 this.fireEvent("mouseout", this, e);
22055 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22058 * @class Roo.bootstrap.menu.Separator
22059 * @extends Roo.bootstrap.Component
22060 * Bootstrap Separator class
22063 * Create a new Separator
22064 * @param {Object} config The config object
22068 Roo.bootstrap.menu.Separator = function(config){
22069 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22072 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22074 getAutoCreate : function(){
22095 * @class Roo.bootstrap.Tooltip
22096 * Bootstrap Tooltip class
22097 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22098 * to determine which dom element triggers the tooltip.
22100 * It needs to add support for additional attributes like tooltip-position
22103 * Create a new Toolti
22104 * @param {Object} config The config object
22107 Roo.bootstrap.Tooltip = function(config){
22108 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22111 Roo.apply(Roo.bootstrap.Tooltip, {
22113 * @function init initialize tooltip monitoring.
22117 currentTip : false,
22118 currentRegion : false,
22124 Roo.get(document).on('mouseover', this.enter ,this);
22125 Roo.get(document).on('mouseout', this.leave, this);
22128 this.currentTip = new Roo.bootstrap.Tooltip();
22131 enter : function(ev)
22133 var dom = ev.getTarget();
22135 //Roo.log(['enter',dom]);
22136 var el = Roo.fly(dom);
22137 if (this.currentEl) {
22139 //Roo.log(this.currentEl);
22140 //Roo.log(this.currentEl.contains(dom));
22141 if (this.currentEl == el) {
22144 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22152 if (this.currentTip.el) {
22153 this.currentTip.el.hide(); // force hiding...
22158 // you can not look for children, as if el is the body.. then everythign is the child..
22159 if (!el.attr('tooltip')) { //
22160 if (!el.select("[tooltip]").elements.length) {
22163 // is the mouse over this child...?
22164 bindEl = el.select("[tooltip]").first();
22165 var xy = ev.getXY();
22166 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22167 //Roo.log("not in region.");
22170 //Roo.log("child element over..");
22173 this.currentEl = bindEl;
22174 this.currentTip.bind(bindEl);
22175 this.currentRegion = Roo.lib.Region.getRegion(dom);
22176 this.currentTip.enter();
22179 leave : function(ev)
22181 var dom = ev.getTarget();
22182 //Roo.log(['leave',dom]);
22183 if (!this.currentEl) {
22188 if (dom != this.currentEl.dom) {
22191 var xy = ev.getXY();
22192 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22195 // only activate leave if mouse cursor is outside... bounding box..
22200 if (this.currentTip) {
22201 this.currentTip.leave();
22203 //Roo.log('clear currentEl');
22204 this.currentEl = false;
22209 'left' : ['r-l', [-2,0], 'right'],
22210 'right' : ['l-r', [2,0], 'left'],
22211 'bottom' : ['t-b', [0,2], 'top'],
22212 'top' : [ 'b-t', [0,-2], 'bottom']
22218 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22223 delay : null, // can be { show : 300 , hide: 500}
22227 hoverState : null, //???
22229 placement : 'bottom',
22231 getAutoCreate : function(){
22238 cls : 'tooltip-arrow'
22241 cls : 'tooltip-inner'
22248 bind : function(el)
22254 enter : function () {
22256 if (this.timeout != null) {
22257 clearTimeout(this.timeout);
22260 this.hoverState = 'in';
22261 //Roo.log("enter - show");
22262 if (!this.delay || !this.delay.show) {
22267 this.timeout = setTimeout(function () {
22268 if (_t.hoverState == 'in') {
22271 }, this.delay.show);
22275 clearTimeout(this.timeout);
22277 this.hoverState = 'out';
22278 if (!this.delay || !this.delay.hide) {
22284 this.timeout = setTimeout(function () {
22285 //Roo.log("leave - timeout");
22287 if (_t.hoverState == 'out') {
22289 Roo.bootstrap.Tooltip.currentEl = false;
22297 this.render(document.body);
22300 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22302 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22304 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22306 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22308 var placement = typeof this.placement == 'function' ?
22309 this.placement.call(this, this.el, on_el) :
22312 var autoToken = /\s?auto?\s?/i;
22313 var autoPlace = autoToken.test(placement);
22315 placement = placement.replace(autoToken, '') || 'top';
22319 //this.el.setXY([0,0]);
22321 //this.el.dom.style.display='block';
22322 this.el.addClass(placement);
22324 //this.el.appendTo(on_el);
22326 var p = this.getPosition();
22327 var box = this.el.getBox();
22332 var align = Roo.bootstrap.Tooltip.alignment[placement];
22333 this.el.alignTo(this.bindEl, align[0],align[1]);
22334 //var arrow = this.el.select('.arrow',true).first();
22335 //arrow.set(align[2],
22337 this.el.addClass('in fade');
22338 this.hoverState = null;
22340 if (this.el.hasClass('fade')) {
22351 //this.el.setXY([0,0]);
22352 this.el.removeClass('in');
22368 * @class Roo.bootstrap.LocationPicker
22369 * @extends Roo.bootstrap.Component
22370 * Bootstrap LocationPicker class
22371 * @cfg {Number} latitude Position when init default 0
22372 * @cfg {Number} longitude Position when init default 0
22373 * @cfg {Number} zoom default 15
22374 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22375 * @cfg {Boolean} mapTypeControl default false
22376 * @cfg {Boolean} disableDoubleClickZoom default false
22377 * @cfg {Boolean} scrollwheel default true
22378 * @cfg {Boolean} streetViewControl default false
22379 * @cfg {Number} radius default 0
22380 * @cfg {String} locationName
22381 * @cfg {Boolean} draggable default true
22382 * @cfg {Boolean} enableAutocomplete default false
22383 * @cfg {Boolean} enableReverseGeocode default true
22384 * @cfg {String} markerTitle
22387 * Create a new LocationPicker
22388 * @param {Object} config The config object
22392 Roo.bootstrap.LocationPicker = function(config){
22394 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22399 * Fires when the picker initialized.
22400 * @param {Roo.bootstrap.LocationPicker} this
22401 * @param {Google Location} location
22405 * @event positionchanged
22406 * Fires when the picker position changed.
22407 * @param {Roo.bootstrap.LocationPicker} this
22408 * @param {Google Location} location
22410 positionchanged : true,
22413 * Fires when the map resize.
22414 * @param {Roo.bootstrap.LocationPicker} this
22419 * Fires when the map show.
22420 * @param {Roo.bootstrap.LocationPicker} this
22425 * Fires when the map hide.
22426 * @param {Roo.bootstrap.LocationPicker} this
22431 * Fires when click the map.
22432 * @param {Roo.bootstrap.LocationPicker} this
22433 * @param {Map event} e
22437 * @event mapRightClick
22438 * Fires when right click the map.
22439 * @param {Roo.bootstrap.LocationPicker} this
22440 * @param {Map event} e
22442 mapRightClick : true,
22444 * @event markerClick
22445 * Fires when click the marker.
22446 * @param {Roo.bootstrap.LocationPicker} this
22447 * @param {Map event} e
22449 markerClick : true,
22451 * @event markerRightClick
22452 * Fires when right click the marker.
22453 * @param {Roo.bootstrap.LocationPicker} this
22454 * @param {Map event} e
22456 markerRightClick : true,
22458 * @event OverlayViewDraw
22459 * Fires when OverlayView Draw
22460 * @param {Roo.bootstrap.LocationPicker} this
22462 OverlayViewDraw : true,
22464 * @event OverlayViewOnAdd
22465 * Fires when OverlayView Draw
22466 * @param {Roo.bootstrap.LocationPicker} this
22468 OverlayViewOnAdd : true,
22470 * @event OverlayViewOnRemove
22471 * Fires when OverlayView Draw
22472 * @param {Roo.bootstrap.LocationPicker} this
22474 OverlayViewOnRemove : true,
22476 * @event OverlayViewShow
22477 * Fires when OverlayView Draw
22478 * @param {Roo.bootstrap.LocationPicker} this
22479 * @param {Pixel} cpx
22481 OverlayViewShow : true,
22483 * @event OverlayViewHide
22484 * Fires when OverlayView Draw
22485 * @param {Roo.bootstrap.LocationPicker} this
22487 OverlayViewHide : true
22492 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22494 gMapContext: false,
22500 mapTypeControl: false,
22501 disableDoubleClickZoom: false,
22503 streetViewControl: false,
22507 enableAutocomplete: false,
22508 enableReverseGeocode: true,
22511 getAutoCreate: function()
22516 cls: 'roo-location-picker'
22522 initEvents: function(ct, position)
22524 if(!this.el.getWidth() || this.isApplied()){
22528 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22533 initial: function()
22535 if(!this.mapTypeId){
22536 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22539 this.gMapContext = this.GMapContext();
22541 this.initOverlayView();
22543 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22547 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22548 _this.setPosition(_this.gMapContext.marker.position);
22551 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22552 _this.fireEvent('mapClick', this, event);
22556 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22557 _this.fireEvent('mapRightClick', this, event);
22561 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22562 _this.fireEvent('markerClick', this, event);
22566 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22567 _this.fireEvent('markerRightClick', this, event);
22571 this.setPosition(this.gMapContext.location);
22573 this.fireEvent('initial', this, this.gMapContext.location);
22576 initOverlayView: function()
22580 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22584 _this.fireEvent('OverlayViewDraw', _this);
22589 _this.fireEvent('OverlayViewOnAdd', _this);
22592 onRemove: function()
22594 _this.fireEvent('OverlayViewOnRemove', _this);
22597 show: function(cpx)
22599 _this.fireEvent('OverlayViewShow', _this, cpx);
22604 _this.fireEvent('OverlayViewHide', _this);
22610 fromLatLngToContainerPixel: function(event)
22612 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22615 isApplied: function()
22617 return this.getGmapContext() == false ? false : true;
22620 getGmapContext: function()
22622 return this.gMapContext
22625 GMapContext: function()
22627 var position = new google.maps.LatLng(this.latitude, this.longitude);
22629 var _map = new google.maps.Map(this.el.dom, {
22632 mapTypeId: this.mapTypeId,
22633 mapTypeControl: this.mapTypeControl,
22634 disableDoubleClickZoom: this.disableDoubleClickZoom,
22635 scrollwheel: this.scrollwheel,
22636 streetViewControl: this.streetViewControl,
22637 locationName: this.locationName,
22638 draggable: this.draggable,
22639 enableAutocomplete: this.enableAutocomplete,
22640 enableReverseGeocode: this.enableReverseGeocode
22643 var _marker = new google.maps.Marker({
22644 position: position,
22646 title: this.markerTitle,
22647 draggable: this.draggable
22654 location: position,
22655 radius: this.radius,
22656 locationName: this.locationName,
22657 addressComponents: {
22658 formatted_address: null,
22659 addressLine1: null,
22660 addressLine2: null,
22662 streetNumber: null,
22666 stateOrProvince: null
22669 domContainer: this.el.dom,
22670 geodecoder: new google.maps.Geocoder()
22674 drawCircle: function(center, radius, options)
22676 if (this.gMapContext.circle != null) {
22677 this.gMapContext.circle.setMap(null);
22681 options = Roo.apply({}, options, {
22682 strokeColor: "#0000FF",
22683 strokeOpacity: .35,
22685 fillColor: "#0000FF",
22689 options.map = this.gMapContext.map;
22690 options.radius = radius;
22691 options.center = center;
22692 this.gMapContext.circle = new google.maps.Circle(options);
22693 return this.gMapContext.circle;
22699 setPosition: function(location)
22701 this.gMapContext.location = location;
22702 this.gMapContext.marker.setPosition(location);
22703 this.gMapContext.map.panTo(location);
22704 this.drawCircle(location, this.gMapContext.radius, {});
22708 if (this.gMapContext.settings.enableReverseGeocode) {
22709 this.gMapContext.geodecoder.geocode({
22710 latLng: this.gMapContext.location
22711 }, function(results, status) {
22713 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22714 _this.gMapContext.locationName = results[0].formatted_address;
22715 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22717 _this.fireEvent('positionchanged', this, location);
22724 this.fireEvent('positionchanged', this, location);
22729 google.maps.event.trigger(this.gMapContext.map, "resize");
22731 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22733 this.fireEvent('resize', this);
22736 setPositionByLatLng: function(latitude, longitude)
22738 this.setPosition(new google.maps.LatLng(latitude, longitude));
22741 getCurrentPosition: function()
22744 latitude: this.gMapContext.location.lat(),
22745 longitude: this.gMapContext.location.lng()
22749 getAddressName: function()
22751 return this.gMapContext.locationName;
22754 getAddressComponents: function()
22756 return this.gMapContext.addressComponents;
22759 address_component_from_google_geocode: function(address_components)
22763 for (var i = 0; i < address_components.length; i++) {
22764 var component = address_components[i];
22765 if (component.types.indexOf("postal_code") >= 0) {
22766 result.postalCode = component.short_name;
22767 } else if (component.types.indexOf("street_number") >= 0) {
22768 result.streetNumber = component.short_name;
22769 } else if (component.types.indexOf("route") >= 0) {
22770 result.streetName = component.short_name;
22771 } else if (component.types.indexOf("neighborhood") >= 0) {
22772 result.city = component.short_name;
22773 } else if (component.types.indexOf("locality") >= 0) {
22774 result.city = component.short_name;
22775 } else if (component.types.indexOf("sublocality") >= 0) {
22776 result.district = component.short_name;
22777 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22778 result.stateOrProvince = component.short_name;
22779 } else if (component.types.indexOf("country") >= 0) {
22780 result.country = component.short_name;
22784 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22785 result.addressLine2 = "";
22789 setZoomLevel: function(zoom)
22791 this.gMapContext.map.setZoom(zoom);
22804 this.fireEvent('show', this);
22815 this.fireEvent('hide', this);
22820 Roo.apply(Roo.bootstrap.LocationPicker, {
22822 OverlayView : function(map, options)
22824 options = options || {};
22838 * @class Roo.bootstrap.Alert
22839 * @extends Roo.bootstrap.Component
22840 * Bootstrap Alert class
22841 * @cfg {String} title The title of alert
22842 * @cfg {String} html The content of alert
22843 * @cfg {String} weight ( success | info | warning | danger )
22844 * @cfg {String} faicon font-awesomeicon
22847 * Create a new alert
22848 * @param {Object} config The config object
22852 Roo.bootstrap.Alert = function(config){
22853 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22857 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22864 getAutoCreate : function()
22873 cls : 'roo-alert-icon'
22878 cls : 'roo-alert-title',
22883 cls : 'roo-alert-text',
22890 cfg.cn[0].cls += ' fa ' + this.faicon;
22894 cfg.cls += ' alert-' + this.weight;
22900 initEvents: function()
22902 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22905 setTitle : function(str)
22907 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22910 setText : function(str)
22912 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22915 setWeight : function(weight)
22918 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22921 this.weight = weight;
22923 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22926 setIcon : function(icon)
22929 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22934 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);