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);
356 * @class Roo.bootstrap.Body
357 * @extends Roo.bootstrap.Component
358 * Bootstrap Body class
362 * @param {Object} config The config object
365 Roo.bootstrap.Body = function(config){
366 Roo.bootstrap.Body.superclass.constructor.call(this, config);
367 this.el = Roo.get(document.body);
368 if (this.cls && this.cls.length) {
369 Roo.get(document.body).addClass(this.cls);
373 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
378 onRender : function(ct, position)
380 /* Roo.log("Roo.bootstrap.Body - onRender");
381 if (this.cls && this.cls.length) {
382 Roo.get(document.body).addClass(this.cls);
402 * @class Roo.bootstrap.ButtonGroup
403 * @extends Roo.bootstrap.Component
404 * Bootstrap ButtonGroup class
405 * @cfg {String} size lg | sm | xs (default empty normal)
406 * @cfg {String} align vertical | justified (default none)
407 * @cfg {String} direction up | down (default down)
408 * @cfg {Boolean} toolbar false | true
409 * @cfg {Boolean} btn true | false
414 * @param {Object} config The config object
417 Roo.bootstrap.ButtonGroup = function(config){
418 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
421 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
429 getAutoCreate : function(){
435 cfg.html = this.html || cfg.html;
446 if (['vertical','justified'].indexOf(this.align)!==-1) {
447 cfg.cls = 'btn-group-' + this.align;
449 if (this.align == 'justified') {
450 console.log(this.items);
454 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
455 cfg.cls += ' btn-group-' + this.size;
458 if (this.direction == 'up') {
459 cfg.cls += ' dropup' ;
475 * @class Roo.bootstrap.Button
476 * @extends Roo.bootstrap.Component
477 * Bootstrap Button class
478 * @cfg {String} html The button content
479 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
480 * @cfg {String} size ( lg | sm | xs)
481 * @cfg {String} tag ( a | input | submit)
482 * @cfg {String} href empty or href
483 * @cfg {Boolean} disabled default false;
484 * @cfg {Boolean} isClose default false;
485 * @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)
486 * @cfg {String} badge text for badge
487 * @cfg {String} theme default
488 * @cfg {Boolean} inverse
489 * @cfg {Boolean} toggle
490 * @cfg {String} ontext text for on toggle state
491 * @cfg {String} offtext text for off toggle state
492 * @cfg {Boolean} defaulton
493 * @cfg {Boolean} preventDefault default true
494 * @cfg {Boolean} removeClass remove the standard class..
495 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
498 * Create a new button
499 * @param {Object} config The config object
503 Roo.bootstrap.Button = function(config){
504 Roo.bootstrap.Button.superclass.constructor.call(this, config);
509 * When a butotn is pressed
510 * @param {Roo.bootstrap.Button} this
511 * @param {Roo.EventObject} e
516 * After the button has been toggles
517 * @param {Roo.EventObject} e
518 * @param {boolean} pressed (also available as button.pressed)
524 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
542 preventDefault: true,
551 getAutoCreate : function(){
559 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
560 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
565 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
567 if (this.toggle == true) {
570 cls: 'slider-frame roo-button',
575 'data-off-text':'OFF',
576 cls: 'slider-button',
582 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
583 cfg.cls += ' '+this.weight;
592 cfg["aria-hidden"] = true;
594 cfg.html = "×";
600 if (this.theme==='default') {
601 cfg.cls = 'btn roo-button';
603 //if (this.parentType != 'Navbar') {
604 this.weight = this.weight.length ? this.weight : 'default';
606 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
608 cfg.cls += ' btn-' + this.weight;
610 } else if (this.theme==='glow') {
613 cfg.cls = 'btn-glow roo-button';
615 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
617 cfg.cls += ' ' + this.weight;
623 this.cls += ' inverse';
628 cfg.cls += ' active';
632 cfg.disabled = 'disabled';
636 Roo.log('changing to ul' );
638 this.glyphicon = 'caret';
641 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
643 //gsRoo.log(this.parentType);
644 if (this.parentType === 'Navbar' && !this.parent().bar) {
645 Roo.log('changing to li?');
654 href : this.href || '#'
657 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
658 cfg.cls += ' dropdown';
665 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
667 if (this.glyphicon) {
668 cfg.html = ' ' + cfg.html;
673 cls: 'glyphicon glyphicon-' + this.glyphicon
683 // cfg.cls='btn roo-button';
687 var value = cfg.html;
692 cls: 'glyphicon glyphicon-' + this.glyphicon,
711 cfg.cls += ' dropdown';
712 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
715 if (cfg.tag !== 'a' && this.href !== '') {
716 throw "Tag must be a to set href.";
717 } else if (this.href.length > 0) {
718 cfg.href = this.href;
721 if(this.removeClass){
726 cfg.target = this.target;
731 initEvents: function() {
732 // Roo.log('init events?');
733 // Roo.log(this.el.dom);
736 if (typeof (this.menu) != 'undefined') {
737 this.menu.parentType = this.xtype;
738 this.menu.triggerEl = this.el;
739 this.addxtype(Roo.apply({}, this.menu));
743 if (this.el.hasClass('roo-button')) {
744 this.el.on('click', this.onClick, this);
746 this.el.select('.roo-button').on('click', this.onClick, this);
749 if(this.removeClass){
750 this.el.on('click', this.onClick, this);
753 this.el.enableDisplayMode();
756 onClick : function(e)
763 Roo.log('button on click ');
764 if(this.preventDefault){
767 if (this.pressed === true || this.pressed === false) {
768 this.pressed = !this.pressed;
769 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
770 this.fireEvent('toggle', this, e, this.pressed);
774 this.fireEvent('click', this, e);
778 * Enables this button
782 this.disabled = false;
783 this.el.removeClass('disabled');
787 * Disable this button
791 this.disabled = true;
792 this.el.addClass('disabled');
795 * sets the active state on/off,
796 * @param {Boolean} state (optional) Force a particular state
798 setActive : function(v) {
800 this.el[v ? 'addClass' : 'removeClass']('active');
803 * toggles the current active state
805 toggleActive : function()
807 var active = this.el.hasClass('active');
808 this.setActive(!active);
812 setText : function(str)
814 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
818 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
841 * @class Roo.bootstrap.Column
842 * @extends Roo.bootstrap.Component
843 * Bootstrap Column class
844 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
845 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
846 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
847 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
848 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
849 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
850 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
851 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
854 * @cfg {Boolean} hidden (true|false) hide the element
855 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
856 * @cfg {String} fa (ban|check|...) font awesome icon
857 * @cfg {Number} fasize (1|2|....) font awsome size
859 * @cfg {String} icon (info-sign|check|...) glyphicon name
861 * @cfg {String} html content of column.
864 * Create a new Column
865 * @param {Object} config The config object
868 Roo.bootstrap.Column = function(config){
869 Roo.bootstrap.Column.superclass.constructor.call(this, config);
872 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
890 getAutoCreate : function(){
891 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
899 ['xs','sm','md','lg'].map(function(size){
900 //Roo.log( size + ':' + settings[size]);
902 if (settings[size+'off'] !== false) {
903 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
906 if (settings[size] === false) {
909 Roo.log(settings[size]);
910 if (!settings[size]) { // 0 = hidden
911 cfg.cls += ' hidden-' + size;
914 cfg.cls += ' col-' + size + '-' + settings[size];
919 cfg.cls += ' hidden';
922 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
923 cfg.cls +=' alert alert-' + this.alert;
927 if (this.html.length) {
928 cfg.html = this.html;
932 if (this.fasize > 1) {
933 fasize = ' fa-' + this.fasize + 'x';
935 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
940 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
959 * @class Roo.bootstrap.Container
960 * @extends Roo.bootstrap.Component
961 * Bootstrap Container class
962 * @cfg {Boolean} jumbotron is it a jumbotron element
963 * @cfg {String} html content of element
964 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
965 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
966 * @cfg {String} header content of header (for panel)
967 * @cfg {String} footer content of footer (for panel)
968 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
969 * @cfg {String} tag (header|aside|section) type of HTML tag.
970 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
971 * @cfg {String} fa (ban|check|...) font awesome icon
972 * @cfg {String} icon (info-sign|check|...) glyphicon name
973 * @cfg {Boolean} hidden (true|false) hide the element
977 * Create a new Container
978 * @param {Object} config The config object
981 Roo.bootstrap.Container = function(config){
982 Roo.bootstrap.Container.superclass.constructor.call(this, config);
985 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
999 getChildContainer : function() {
1005 if (this.panel.length) {
1006 return this.el.select('.panel-body',true).first();
1013 getAutoCreate : function(){
1016 tag : this.tag || 'div',
1020 if (this.jumbotron) {
1021 cfg.cls = 'jumbotron';
1026 // - this is applied by the parent..
1028 // cfg.cls = this.cls + '';
1031 if (this.sticky.length) {
1033 var bd = Roo.get(document.body);
1034 if (!bd.hasClass('bootstrap-sticky')) {
1035 bd.addClass('bootstrap-sticky');
1036 Roo.select('html',true).setStyle('height', '100%');
1039 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1043 if (this.well.length) {
1044 switch (this.well) {
1047 cfg.cls +=' well well-' +this.well;
1056 cfg.cls += ' hidden';
1060 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1061 cfg.cls +=' alert alert-' + this.alert;
1066 if (this.panel.length) {
1067 cfg.cls += ' panel panel-' + this.panel;
1069 if (this.header.length) {
1072 cls : 'panel-heading',
1075 cls : 'panel-title',
1088 if (this.footer.length) {
1090 cls : 'panel-footer',
1099 body.html = this.html || cfg.html;
1100 // prefix with the icons..
1102 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1105 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1110 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1111 cfg.cls = 'container';
1117 titleEl : function()
1119 if(!this.el || !this.panel.length || !this.header.length){
1123 return this.el.select('.panel-title',true).first();
1126 setTitle : function(v)
1128 var titleEl = this.titleEl();
1134 titleEl.dom.innerHTML = v;
1137 getTitle : function()
1140 var titleEl = this.titleEl();
1146 return titleEl.dom.innerHTML;
1150 this.el.removeClass('hidden');
1153 if (!this.el.hasClass('hidden')) {
1154 this.el.addClass('hidden');
1170 * @class Roo.bootstrap.Img
1171 * @extends Roo.bootstrap.Component
1172 * Bootstrap Img class
1173 * @cfg {Boolean} imgResponsive false | true
1174 * @cfg {String} border rounded | circle | thumbnail
1175 * @cfg {String} src image source
1176 * @cfg {String} alt image alternative text
1177 * @cfg {String} href a tag href
1178 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1181 * Create a new Input
1182 * @param {Object} config The config object
1185 Roo.bootstrap.Img = function(config){
1186 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1192 * The img click event for the img.
1193 * @param {Roo.EventObject} e
1199 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1201 imgResponsive: true,
1207 getAutoCreate : function(){
1211 cls: (this.imgResponsive) ? 'img-responsive' : '',
1215 cfg.html = this.html || cfg.html;
1217 cfg.src = this.src || cfg.src;
1219 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1220 cfg.cls += ' img-' + this.border;
1237 a.target = this.target;
1243 return (this.href) ? a : cfg;
1246 initEvents: function() {
1249 this.el.on('click', this.onClick, this);
1253 onClick : function(e)
1255 Roo.log('img onclick');
1256 this.fireEvent('click', this, e);
1270 * @class Roo.bootstrap.Link
1271 * @extends Roo.bootstrap.Component
1272 * Bootstrap Link Class
1273 * @cfg {String} alt image alternative text
1274 * @cfg {String} href a tag href
1275 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1276 * @cfg {String} html the content of the link.
1277 * @cfg {String} anchor name for the anchor link
1279 * @cfg {Boolean} preventDefault (true | false) default false
1283 * Create a new Input
1284 * @param {Object} config The config object
1287 Roo.bootstrap.Link = function(config){
1288 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1294 * The img click event for the img.
1295 * @param {Roo.EventObject} e
1301 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1305 preventDefault: false,
1309 getAutoCreate : function()
1315 // anchor's do not require html/href...
1316 if (this.anchor === false) {
1317 cfg.html = this.html || 'html-missing';
1318 cfg.href = this.href || '#';
1320 cfg.name = this.anchor;
1321 if (this.html !== false) {
1322 cfg.html = this.html;
1324 if (this.href !== false) {
1325 cfg.href = this.href;
1329 if(this.alt !== false){
1334 if(this.target !== false) {
1335 cfg.target = this.target;
1341 initEvents: function() {
1343 if(!this.href || this.preventDefault){
1344 this.el.on('click', this.onClick, this);
1348 onClick : function(e)
1350 if(this.preventDefault){
1353 //Roo.log('img onclick');
1354 this.fireEvent('click', this, e);
1367 * @class Roo.bootstrap.Header
1368 * @extends Roo.bootstrap.Component
1369 * Bootstrap Header class
1370 * @cfg {String} html content of header
1371 * @cfg {Number} level (1|2|3|4|5|6) default 1
1374 * Create a new Header
1375 * @param {Object} config The config object
1379 Roo.bootstrap.Header = function(config){
1380 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1383 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1391 getAutoCreate : function(){
1396 tag: 'h' + (1 *this.level),
1397 html: this.html || ''
1409 * Ext JS Library 1.1.1
1410 * Copyright(c) 2006-2007, Ext JS, LLC.
1412 * Originally Released Under LGPL - original licence link has changed is not relivant.
1415 * <script type="text/javascript">
1419 * @class Roo.bootstrap.MenuMgr
1420 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1423 Roo.bootstrap.MenuMgr = function(){
1424 var menus, active, groups = {}, attached = false, lastShow = new Date();
1426 // private - called when first menu is created
1429 active = new Roo.util.MixedCollection();
1430 Roo.get(document).addKeyListener(27, function(){
1431 if(active.length > 0){
1439 if(active && active.length > 0){
1440 var c = active.clone();
1450 if(active.length < 1){
1451 Roo.get(document).un("mouseup", onMouseDown);
1459 var last = active.last();
1460 lastShow = new Date();
1463 Roo.get(document).on("mouseup", onMouseDown);
1468 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1469 m.parentMenu.activeChild = m;
1470 }else if(last && last.isVisible()){
1471 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1476 function onBeforeHide(m){
1478 m.activeChild.hide();
1480 if(m.autoHideTimer){
1481 clearTimeout(m.autoHideTimer);
1482 delete m.autoHideTimer;
1487 function onBeforeShow(m){
1488 var pm = m.parentMenu;
1489 if(!pm && !m.allowOtherMenus){
1491 }else if(pm && pm.activeChild && active != m){
1492 pm.activeChild.hide();
1497 function onMouseDown(e){
1498 Roo.log("on MouseDown");
1499 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1507 function onBeforeCheck(mi, state){
1509 var g = groups[mi.group];
1510 for(var i = 0, l = g.length; i < l; i++){
1512 g[i].setChecked(false);
1521 * Hides all menus that are currently visible
1523 hideAll : function(){
1528 register : function(menu){
1532 menus[menu.id] = menu;
1533 menu.on("beforehide", onBeforeHide);
1534 menu.on("hide", onHide);
1535 menu.on("beforeshow", onBeforeShow);
1536 menu.on("show", onShow);
1538 if(g && menu.events["checkchange"]){
1542 groups[g].push(menu);
1543 menu.on("checkchange", onCheck);
1548 * Returns a {@link Roo.menu.Menu} object
1549 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1550 * be used to generate and return a new Menu instance.
1552 get : function(menu){
1553 if(typeof menu == "string"){ // menu id
1555 }else if(menu.events){ // menu instance
1558 /*else if(typeof menu.length == 'number'){ // array of menu items?
1559 return new Roo.bootstrap.Menu({items:menu});
1560 }else{ // otherwise, must be a config
1561 return new Roo.bootstrap.Menu(menu);
1568 unregister : function(menu){
1569 delete menus[menu.id];
1570 menu.un("beforehide", onBeforeHide);
1571 menu.un("hide", onHide);
1572 menu.un("beforeshow", onBeforeShow);
1573 menu.un("show", onShow);
1575 if(g && menu.events["checkchange"]){
1576 groups[g].remove(menu);
1577 menu.un("checkchange", onCheck);
1582 registerCheckable : function(menuItem){
1583 var g = menuItem.group;
1588 groups[g].push(menuItem);
1589 menuItem.on("beforecheckchange", onBeforeCheck);
1594 unregisterCheckable : function(menuItem){
1595 var g = menuItem.group;
1597 groups[g].remove(menuItem);
1598 menuItem.un("beforecheckchange", onBeforeCheck);
1610 * @class Roo.bootstrap.Menu
1611 * @extends Roo.bootstrap.Component
1612 * Bootstrap Menu class - container for MenuItems
1613 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1617 * @param {Object} config The config object
1621 Roo.bootstrap.Menu = function(config){
1622 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1623 if (this.registerMenu) {
1624 Roo.bootstrap.MenuMgr.register(this);
1629 * Fires before this menu is displayed
1630 * @param {Roo.menu.Menu} this
1635 * Fires before this menu is hidden
1636 * @param {Roo.menu.Menu} this
1641 * Fires after this menu is displayed
1642 * @param {Roo.menu.Menu} this
1647 * Fires after this menu is hidden
1648 * @param {Roo.menu.Menu} this
1653 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1654 * @param {Roo.menu.Menu} this
1655 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1656 * @param {Roo.EventObject} e
1661 * Fires when the mouse is hovering over this menu
1662 * @param {Roo.menu.Menu} this
1663 * @param {Roo.EventObject} e
1664 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1669 * Fires when the mouse exits this menu
1670 * @param {Roo.menu.Menu} this
1671 * @param {Roo.EventObject} e
1672 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1677 * Fires when a menu item contained in this menu is clicked
1678 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1679 * @param {Roo.EventObject} e
1683 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1686 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1690 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1693 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1695 registerMenu : true,
1697 menuItems :false, // stores the menu items..
1703 getChildContainer : function() {
1707 getAutoCreate : function(){
1709 //if (['right'].indexOf(this.align)!==-1) {
1710 // cfg.cn[1].cls += ' pull-right'
1716 cls : 'dropdown-menu' ,
1717 style : 'z-index:1000'
1721 if (this.type === 'submenu') {
1722 cfg.cls = 'submenu active';
1724 if (this.type === 'treeview') {
1725 cfg.cls = 'treeview-menu';
1730 initEvents : function() {
1732 // Roo.log("ADD event");
1733 // Roo.log(this.triggerEl.dom);
1734 this.triggerEl.on('click', this.onTriggerPress, this);
1735 this.triggerEl.addClass('dropdown-toggle');
1736 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1738 this.el.on("mouseover", this.onMouseOver, this);
1739 this.el.on("mouseout", this.onMouseOut, this);
1743 findTargetItem : function(e){
1744 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1748 //Roo.log(t); Roo.log(t.id);
1750 //Roo.log(this.menuitems);
1751 return this.menuitems.get(t.id);
1753 //return this.items.get(t.menuItemId);
1758 onClick : function(e){
1759 Roo.log("menu.onClick");
1760 var t = this.findTargetItem(e);
1761 if(!t || t.isContainer){
1766 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1767 if(t == this.activeItem && t.shouldDeactivate(e)){
1768 this.activeItem.deactivate();
1769 delete this.activeItem;
1773 this.setActiveItem(t, true);
1781 Roo.log('pass click event');
1785 this.fireEvent("click", this, t, e);
1789 onMouseOver : function(e){
1790 var t = this.findTargetItem(e);
1793 // if(t.canActivate && !t.disabled){
1794 // this.setActiveItem(t, true);
1798 this.fireEvent("mouseover", this, e, t);
1800 isVisible : function(){
1801 return !this.hidden;
1803 onMouseOut : function(e){
1804 var t = this.findTargetItem(e);
1807 // if(t == this.activeItem && t.shouldDeactivate(e)){
1808 // this.activeItem.deactivate();
1809 // delete this.activeItem;
1812 this.fireEvent("mouseout", this, e, t);
1817 * Displays this menu relative to another element
1818 * @param {String/HTMLElement/Roo.Element} element The element to align to
1819 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1820 * the element (defaults to this.defaultAlign)
1821 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1823 show : function(el, pos, parentMenu){
1824 this.parentMenu = parentMenu;
1828 this.fireEvent("beforeshow", this);
1829 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1832 * Displays this menu at a specific xy position
1833 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1834 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1836 showAt : function(xy, parentMenu, /* private: */_e){
1837 this.parentMenu = parentMenu;
1842 this.fireEvent("beforeshow", this);
1843 //xy = this.el.adjustForConstraints(xy);
1847 this.hideMenuItems();
1848 this.hidden = false;
1849 this.triggerEl.addClass('open');
1851 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1852 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1857 this.fireEvent("show", this);
1863 this.doFocus.defer(50, this);
1867 doFocus : function(){
1869 this.focusEl.focus();
1874 * Hides this menu and optionally all parent menus
1875 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1877 hide : function(deep){
1879 this.hideMenuItems();
1880 if(this.el && this.isVisible()){
1881 this.fireEvent("beforehide", this);
1882 if(this.activeItem){
1883 this.activeItem.deactivate();
1884 this.activeItem = null;
1886 this.triggerEl.removeClass('open');;
1888 this.fireEvent("hide", this);
1890 if(deep === true && this.parentMenu){
1891 this.parentMenu.hide(true);
1895 onTriggerPress : function(e)
1898 Roo.log('trigger press');
1899 //Roo.log(e.getTarget());
1900 // Roo.log(this.triggerEl.dom);
1901 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1904 if (this.isVisible()) {
1908 this.show(this.triggerEl, false, false);
1917 hideMenuItems : function()
1919 //$(backdrop).remove()
1920 Roo.select('.open',true).each(function(aa) {
1922 aa.removeClass('open');
1923 //var parent = getParent($(this))
1924 //var relatedTarget = { relatedTarget: this }
1926 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1927 //if (e.isDefaultPrevented()) return
1928 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1931 addxtypeChild : function (tree, cntr) {
1932 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1934 this.menuitems.add(comp);
1955 * @class Roo.bootstrap.MenuItem
1956 * @extends Roo.bootstrap.Component
1957 * Bootstrap MenuItem class
1958 * @cfg {String} html the menu label
1959 * @cfg {String} href the link
1960 * @cfg {Boolean} preventDefault (true | false) default true
1961 * @cfg {Boolean} isContainer (true | false) default false
1965 * Create a new MenuItem
1966 * @param {Object} config The config object
1970 Roo.bootstrap.MenuItem = function(config){
1971 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1976 * The raw click event for the entire grid.
1977 * @param {Roo.bootstrap.MenuItem} this
1978 * @param {Roo.EventObject} e
1984 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1988 preventDefault: true,
1989 isContainer : false,
1991 getAutoCreate : function(){
1993 if(this.isContainer){
1996 cls: 'dropdown-menu-item'
2002 cls: 'dropdown-menu-item',
2011 if (this.parent().type == 'treeview') {
2012 cfg.cls = 'treeview-menu';
2015 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2016 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2020 initEvents: function() {
2022 //this.el.select('a').on('click', this.onClick, this);
2025 onClick : function(e)
2027 Roo.log('item on click ');
2028 //if(this.preventDefault){
2029 // e.preventDefault();
2031 //this.parent().hideMenuItems();
2033 this.fireEvent('click', this, e);
2052 * @class Roo.bootstrap.MenuSeparator
2053 * @extends Roo.bootstrap.Component
2054 * Bootstrap MenuSeparator class
2057 * Create a new MenuItem
2058 * @param {Object} config The config object
2062 Roo.bootstrap.MenuSeparator = function(config){
2063 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2066 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2068 getAutoCreate : function(){
2087 * @class Roo.bootstrap.Modal
2088 * @extends Roo.bootstrap.Component
2089 * Bootstrap Modal class
2090 * @cfg {String} title Title of dialog
2091 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2092 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2093 * @cfg {Boolean} specificTitle default false
2094 * @cfg {Array} buttons Array of buttons or standard button set..
2095 * @cfg {String} buttonPosition (left|right|center) default right
2096 * @cfg {Boolean} animate default true
2097 * @cfg {Boolean} allow_close default true
2100 * Create a new Modal Dialog
2101 * @param {Object} config The config object
2104 Roo.bootstrap.Modal = function(config){
2105 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2110 * The raw btnclick event for the button
2111 * @param {Roo.EventObject} e
2115 this.buttons = this.buttons || [];
2118 this.tmpl = Roo.factory(this.tmpl);
2123 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2125 title : 'test dialog',
2135 specificTitle: false,
2137 buttonPosition: 'right',
2151 onRender : function(ct, position)
2153 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2156 var cfg = Roo.apply({}, this.getAutoCreate());
2159 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2161 //if (!cfg.name.length) {
2165 cfg.cls += ' ' + this.cls;
2168 cfg.style = this.style;
2170 this.el = Roo.get(document.body).createChild(cfg, position);
2172 //var type = this.el.dom.type;
2177 if(this.tabIndex !== undefined){
2178 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2182 this.bodyEl = this.el.select('.modal-body',true).first();
2183 this.closeEl = this.el.select('.modal-header .close', true).first();
2184 this.footerEl = this.el.select('.modal-footer',true).first();
2185 this.titleEl = this.el.select('.modal-title',true).first();
2189 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2190 this.maskEl.enableDisplayMode("block");
2192 //this.el.addClass("x-dlg-modal");
2194 if (this.buttons.length) {
2195 Roo.each(this.buttons, function(bb) {
2196 b = Roo.apply({}, bb);
2197 b.xns = b.xns || Roo.bootstrap;
2198 b.xtype = b.xtype || 'Button';
2199 if (typeof(b.listeners) == 'undefined') {
2200 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2203 var btn = Roo.factory(b);
2205 btn.onRender(this.el.select('.modal-footer div').first());
2209 // render the children.
2212 if(typeof(this.items) != 'undefined'){
2213 var items = this.items;
2216 for(var i =0;i < items.length;i++) {
2217 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2221 this.items = nitems;
2223 // where are these used - they used to be body/close/footer
2227 //this.el.addClass([this.fieldClass, this.cls]);
2230 getAutoCreate : function(){
2235 html : this.html || ''
2240 cls : 'modal-title',
2244 if(this.specificTitle){
2250 if (this.allow_close) {
2261 style : 'display: none',
2264 cls: "modal-dialog",
2267 cls : "modal-content",
2270 cls : 'modal-header',
2275 cls : 'modal-footer',
2279 cls: 'btn-' + this.buttonPosition
2296 modal.cls += ' fade';
2302 getChildContainer : function() {
2307 getButtonContainer : function() {
2308 return this.el.select('.modal-footer div',true).first();
2311 initEvents : function()
2313 if (this.allow_close) {
2314 this.closeEl.on('click', this.hide, this);
2320 if (!this.rendered) {
2324 this.el.setStyle('display', 'block');
2328 (function(){ _this.el.addClass('in'); }).defer(50);
2330 this.el.addClass('in');
2333 // not sure how we can show data in here..
2335 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2338 Roo.get(document.body).addClass("x-body-masked");
2339 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2341 this.el.setStyle('zIndex', '10001');
2343 this.fireEvent('show', this);
2350 Roo.get(document.body).removeClass("x-body-masked");
2351 this.el.removeClass('in');
2355 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2357 this.el.setStyle('display', 'none');
2360 this.fireEvent('hide', this);
2363 addButton : function(str, cb)
2367 var b = Roo.apply({}, { html : str } );
2368 b.xns = b.xns || Roo.bootstrap;
2369 b.xtype = b.xtype || 'Button';
2370 if (typeof(b.listeners) == 'undefined') {
2371 b.listeners = { click : cb.createDelegate(this) };
2374 var btn = Roo.factory(b);
2376 btn.onRender(this.el.select('.modal-footer div').first());
2382 setDefaultButton : function(btn)
2384 //this.el.select('.modal-footer').()
2386 resizeTo: function(w,h)
2390 setContentSize : function(w, h)
2394 onButtonClick: function(btn,e)
2397 this.fireEvent('btnclick', btn.name, e);
2400 * Set the title of the Dialog
2401 * @param {String} str new Title
2403 setTitle: function(str) {
2404 this.titleEl.dom.innerHTML = str;
2407 * Set the body of the Dialog
2408 * @param {String} str new Title
2410 setBody: function(str) {
2411 this.bodyEl.dom.innerHTML = str;
2414 * Set the body of the Dialog using the template
2415 * @param {Obj} data - apply this data to the template and replace the body contents.
2417 applyBody: function(obj)
2420 Roo.log("Error - using apply Body without a template");
2423 this.tmpl.overwrite(this.bodyEl, obj);
2429 Roo.apply(Roo.bootstrap.Modal, {
2431 * Button config that displays a single OK button
2440 * Button config that displays Yes and No buttons
2456 * Button config that displays OK and Cancel buttons
2471 * Button config that displays Yes, No and Cancel buttons
2494 * messagebox - can be used as a replace
2498 * @class Roo.MessageBox
2499 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2503 Roo.Msg.alert('Status', 'Changes saved successfully.');
2505 // Prompt for user data:
2506 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2508 // process text value...
2512 // Show a dialog using config options:
2514 title:'Save Changes?',
2515 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2516 buttons: Roo.Msg.YESNOCANCEL,
2523 Roo.bootstrap.MessageBox = function(){
2524 var dlg, opt, mask, waitTimer;
2525 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2526 var buttons, activeTextEl, bwidth;
2530 var handleButton = function(button){
2532 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2536 var handleHide = function(){
2538 dlg.el.removeClass(opt.cls);
2541 // Roo.TaskMgr.stop(waitTimer);
2542 // waitTimer = null;
2547 var updateButtons = function(b){
2550 buttons["ok"].hide();
2551 buttons["cancel"].hide();
2552 buttons["yes"].hide();
2553 buttons["no"].hide();
2554 //dlg.footer.dom.style.display = 'none';
2557 dlg.footerEl.dom.style.display = '';
2558 for(var k in buttons){
2559 if(typeof buttons[k] != "function"){
2562 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2563 width += buttons[k].el.getWidth()+15;
2573 var handleEsc = function(d, k, e){
2574 if(opt && opt.closable !== false){
2584 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2585 * @return {Roo.BasicDialog} The BasicDialog element
2587 getDialog : function(){
2589 dlg = new Roo.bootstrap.Modal( {
2592 //constraintoviewport:false,
2594 //collapsible : false,
2599 //buttonAlign:"center",
2600 closeClick : function(){
2601 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2604 handleButton("cancel");
2609 dlg.on("hide", handleHide);
2611 //dlg.addKeyListener(27, handleEsc);
2613 this.buttons = buttons;
2614 var bt = this.buttonText;
2615 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2616 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2617 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2618 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2620 bodyEl = dlg.bodyEl.createChild({
2622 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2623 '<textarea class="roo-mb-textarea"></textarea>' +
2624 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2626 msgEl = bodyEl.dom.firstChild;
2627 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2628 textboxEl.enableDisplayMode();
2629 textboxEl.addKeyListener([10,13], function(){
2630 if(dlg.isVisible() && opt && opt.buttons){
2633 }else if(opt.buttons.yes){
2634 handleButton("yes");
2638 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2639 textareaEl.enableDisplayMode();
2640 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2641 progressEl.enableDisplayMode();
2642 var pf = progressEl.dom.firstChild;
2644 pp = Roo.get(pf.firstChild);
2645 pp.setHeight(pf.offsetHeight);
2653 * Updates the message box body text
2654 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2655 * the XHTML-compliant non-breaking space character '&#160;')
2656 * @return {Roo.MessageBox} This message box
2658 updateText : function(text){
2659 if(!dlg.isVisible() && !opt.width){
2660 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2662 msgEl.innerHTML = text || ' ';
2664 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2665 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2667 Math.min(opt.width || cw , this.maxWidth),
2668 Math.max(opt.minWidth || this.minWidth, bwidth)
2671 activeTextEl.setWidth(w);
2673 if(dlg.isVisible()){
2674 dlg.fixedcenter = false;
2676 // to big, make it scroll. = But as usual stupid IE does not support
2679 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2680 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2681 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2683 bodyEl.dom.style.height = '';
2684 bodyEl.dom.style.overflowY = '';
2687 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2689 bodyEl.dom.style.overflowX = '';
2692 dlg.setContentSize(w, bodyEl.getHeight());
2693 if(dlg.isVisible()){
2694 dlg.fixedcenter = true;
2700 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2701 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2702 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2703 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2704 * @return {Roo.MessageBox} This message box
2706 updateProgress : function(value, text){
2708 this.updateText(text);
2710 if (pp) { // weird bug on my firefox - for some reason this is not defined
2711 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2717 * Returns true if the message box is currently displayed
2718 * @return {Boolean} True if the message box is visible, else false
2720 isVisible : function(){
2721 return dlg && dlg.isVisible();
2725 * Hides the message box if it is displayed
2728 if(this.isVisible()){
2734 * Displays a new message box, or reinitializes an existing message box, based on the config options
2735 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2736 * The following config object properties are supported:
2738 Property Type Description
2739 ---------- --------------- ------------------------------------------------------------------------------------
2740 animEl String/Element An id or Element from which the message box should animate as it opens and
2741 closes (defaults to undefined)
2742 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2743 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2744 closable Boolean False to hide the top-right close button (defaults to true). Note that
2745 progress and wait dialogs will ignore this property and always hide the
2746 close button as they can only be closed programmatically.
2747 cls String A custom CSS class to apply to the message box element
2748 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2749 displayed (defaults to 75)
2750 fn Function A callback function to execute after closing the dialog. The arguments to the
2751 function will be btn (the name of the button that was clicked, if applicable,
2752 e.g. "ok"), and text (the value of the active text field, if applicable).
2753 Progress and wait dialogs will ignore this option since they do not respond to
2754 user actions and can only be closed programmatically, so any required function
2755 should be called by the same code after it closes the dialog.
2756 icon String A CSS class that provides a background image to be used as an icon for
2757 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2758 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2759 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2760 modal Boolean False to allow user interaction with the page while the message box is
2761 displayed (defaults to true)
2762 msg String A string that will replace the existing message box body text (defaults
2763 to the XHTML-compliant non-breaking space character ' ')
2764 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2765 progress Boolean True to display a progress bar (defaults to false)
2766 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2767 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2768 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2769 title String The title text
2770 value String The string value to set into the active textbox element if displayed
2771 wait Boolean True to display a progress bar (defaults to false)
2772 width Number The width of the dialog in pixels
2779 msg: 'Please enter your address:',
2781 buttons: Roo.MessageBox.OKCANCEL,
2784 animEl: 'addAddressBtn'
2787 * @param {Object} config Configuration options
2788 * @return {Roo.MessageBox} This message box
2790 show : function(options)
2793 // this causes nightmares if you show one dialog after another
2794 // especially on callbacks..
2796 if(this.isVisible()){
2799 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2800 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2801 Roo.log("New Dialog Message:" + options.msg )
2802 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2803 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2806 var d = this.getDialog();
2808 d.setTitle(opt.title || " ");
2809 d.closeEl.setDisplayed(opt.closable !== false);
2810 activeTextEl = textboxEl;
2811 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2816 textareaEl.setHeight(typeof opt.multiline == "number" ?
2817 opt.multiline : this.defaultTextHeight);
2818 activeTextEl = textareaEl;
2827 progressEl.setDisplayed(opt.progress === true);
2828 this.updateProgress(0);
2829 activeTextEl.dom.value = opt.value || "";
2831 dlg.setDefaultButton(activeTextEl);
2833 var bs = opt.buttons;
2837 }else if(bs && bs.yes){
2838 db = buttons["yes"];
2840 dlg.setDefaultButton(db);
2842 bwidth = updateButtons(opt.buttons);
2843 this.updateText(opt.msg);
2845 d.el.addClass(opt.cls);
2847 d.proxyDrag = opt.proxyDrag === true;
2848 d.modal = opt.modal !== false;
2849 d.mask = opt.modal !== false ? mask : false;
2851 // force it to the end of the z-index stack so it gets a cursor in FF
2852 document.body.appendChild(dlg.el.dom);
2853 d.animateTarget = null;
2854 d.show(options.animEl);
2860 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2861 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2862 * and closing the message box when the process is complete.
2863 * @param {String} title The title bar text
2864 * @param {String} msg The message box body text
2865 * @return {Roo.MessageBox} This message box
2867 progress : function(title, msg){
2874 minWidth: this.minProgressWidth,
2881 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2882 * If a callback function is passed it will be called after the user clicks the button, and the
2883 * id of the button that was clicked will be passed as the only parameter to the callback
2884 * (could also be the top-right close button).
2885 * @param {String} title The title bar text
2886 * @param {String} msg The message box body text
2887 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2888 * @param {Object} scope (optional) The scope of the callback function
2889 * @return {Roo.MessageBox} This message box
2891 alert : function(title, msg, fn, scope){
2904 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2905 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2906 * You are responsible for closing the message box when the process is complete.
2907 * @param {String} msg The message box body text
2908 * @param {String} title (optional) The title bar text
2909 * @return {Roo.MessageBox} This message box
2911 wait : function(msg, title){
2922 waitTimer = Roo.TaskMgr.start({
2924 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2932 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2933 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2934 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2935 * @param {String} title The title bar text
2936 * @param {String} msg The message box body text
2937 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2938 * @param {Object} scope (optional) The scope of the callback function
2939 * @return {Roo.MessageBox} This message box
2941 confirm : function(title, msg, fn, scope){
2945 buttons: this.YESNO,
2954 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2955 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2956 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2957 * (could also be the top-right close button) and the text that was entered will be passed as the two
2958 * parameters to the callback.
2959 * @param {String} title The title bar text
2960 * @param {String} msg The message box body text
2961 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2962 * @param {Object} scope (optional) The scope of the callback function
2963 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2964 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2965 * @return {Roo.MessageBox} This message box
2967 prompt : function(title, msg, fn, scope, multiline){
2971 buttons: this.OKCANCEL,
2976 multiline: multiline,
2983 * Button config that displays a single OK button
2988 * Button config that displays Yes and No buttons
2991 YESNO : {yes:true, no:true},
2993 * Button config that displays OK and Cancel buttons
2996 OKCANCEL : {ok:true, cancel:true},
2998 * Button config that displays Yes, No and Cancel buttons
3001 YESNOCANCEL : {yes:true, no:true, cancel:true},
3004 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3007 defaultTextHeight : 75,
3009 * The maximum width in pixels of the message box (defaults to 600)
3014 * The minimum width in pixels of the message box (defaults to 100)
3019 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3020 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3023 minProgressWidth : 250,
3025 * An object containing the default button text strings that can be overriden for localized language support.
3026 * Supported properties are: ok, cancel, yes and no.
3027 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3040 * Shorthand for {@link Roo.MessageBox}
3042 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3043 Roo.Msg = Roo.Msg || Roo.MessageBox;
3052 * @class Roo.bootstrap.Navbar
3053 * @extends Roo.bootstrap.Component
3054 * Bootstrap Navbar class
3057 * Create a new Navbar
3058 * @param {Object} config The config object
3062 Roo.bootstrap.Navbar = function(config){
3063 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3067 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3076 getAutoCreate : function(){
3079 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3083 initEvents :function ()
3085 //Roo.log(this.el.select('.navbar-toggle',true));
3086 this.el.select('.navbar-toggle',true).on('click', function() {
3087 // Roo.log('click');
3088 this.el.select('.navbar-collapse',true).toggleClass('in');
3096 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3098 var size = this.el.getSize();
3099 this.maskEl.setSize(size.width, size.height);
3100 this.maskEl.enableDisplayMode("block");
3109 getChildContainer : function()
3111 if (this.el.select('.collapse').getCount()) {
3112 return this.el.select('.collapse',true).first();
3145 * @class Roo.bootstrap.NavSimplebar
3146 * @extends Roo.bootstrap.Navbar
3147 * Bootstrap Sidebar class
3149 * @cfg {Boolean} inverse is inverted color
3151 * @cfg {String} type (nav | pills | tabs)
3152 * @cfg {Boolean} arrangement stacked | justified
3153 * @cfg {String} align (left | right) alignment
3155 * @cfg {Boolean} main (true|false) main nav bar? default false
3156 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3158 * @cfg {String} tag (header|footer|nav|div) default is nav
3164 * Create a new Sidebar
3165 * @param {Object} config The config object
3169 Roo.bootstrap.NavSimplebar = function(config){
3170 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3173 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3189 getAutoCreate : function(){
3193 tag : this.tag || 'div',
3206 this.type = this.type || 'nav';
3207 if (['tabs','pills'].indexOf(this.type)!==-1) {
3208 cfg.cn[0].cls += ' nav-' + this.type
3212 if (this.type!=='nav') {
3213 Roo.log('nav type must be nav/tabs/pills')
3215 cfg.cn[0].cls += ' navbar-nav'
3221 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3222 cfg.cn[0].cls += ' nav-' + this.arrangement;
3226 if (this.align === 'right') {
3227 cfg.cn[0].cls += ' navbar-right';
3231 cfg.cls += ' navbar-inverse';
3258 * @class Roo.bootstrap.NavHeaderbar
3259 * @extends Roo.bootstrap.NavSimplebar
3260 * Bootstrap Sidebar class
3262 * @cfg {String} brand what is brand
3263 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3264 * @cfg {String} brand_href href of the brand
3265 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3266 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3267 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3268 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3271 * Create a new Sidebar
3272 * @param {Object} config The config object
3276 Roo.bootstrap.NavHeaderbar = function(config){
3277 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3281 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3288 desktopCenter : false,
3291 getAutoCreate : function(){
3294 tag: this.nav || 'nav',
3301 if (this.desktopCenter) {
3302 cn.push({cls : 'container', cn : []});
3309 cls: 'navbar-header',
3314 cls: 'navbar-toggle',
3315 'data-toggle': 'collapse',
3320 html: 'Toggle navigation'
3342 cls: 'collapse navbar-collapse',
3346 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3348 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3349 cfg.cls += ' navbar-' + this.position;
3351 // tag can override this..
3353 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3356 if (this.brand !== '') {
3359 href: this.brand_href ? this.brand_href : '#',
3360 cls: 'navbar-brand',
3368 cfg.cls += ' main-nav';
3376 getHeaderChildContainer : function()
3378 if (this.el.select('.navbar-header').getCount()) {
3379 return this.el.select('.navbar-header',true).first();
3382 return this.getChildContainer();
3386 initEvents : function()
3388 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3390 if (this.autohide) {
3395 Roo.get(document).on('scroll',function(e) {
3396 var ns = Roo.get(document).getScroll().top;
3397 var os = prevScroll;
3401 ft.removeClass('slideDown');
3402 ft.addClass('slideUp');
3405 ft.removeClass('slideUp');
3406 ft.addClass('slideDown');
3427 * @class Roo.bootstrap.NavSidebar
3428 * @extends Roo.bootstrap.Navbar
3429 * Bootstrap Sidebar class
3432 * Create a new Sidebar
3433 * @param {Object} config The config object
3437 Roo.bootstrap.NavSidebar = function(config){
3438 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3441 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3443 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3445 getAutoCreate : function(){
3450 cls: 'sidebar sidebar-nav'
3472 * @class Roo.bootstrap.NavGroup
3473 * @extends Roo.bootstrap.Component
3474 * Bootstrap NavGroup class
3475 * @cfg {String} align left | right
3476 * @cfg {Boolean} inverse false | true
3477 * @cfg {String} type (nav|pills|tab) default nav
3478 * @cfg {String} navId - reference Id for navbar.
3482 * Create a new nav group
3483 * @param {Object} config The config object
3486 Roo.bootstrap.NavGroup = function(config){
3487 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3490 Roo.bootstrap.NavGroup.register(this);
3494 * Fires when the active item changes
3495 * @param {Roo.bootstrap.NavGroup} this
3496 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3497 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3504 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3515 getAutoCreate : function()
3517 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3524 if (['tabs','pills'].indexOf(this.type)!==-1) {
3525 cfg.cls += ' nav-' + this.type
3527 if (this.type!=='nav') {
3528 Roo.log('nav type must be nav/tabs/pills')
3530 cfg.cls += ' navbar-nav'
3533 if (this.parent().sidebar) {
3536 cls: 'dashboard-menu sidebar-menu'
3542 if (this.form === true) {
3548 if (this.align === 'right') {
3549 cfg.cls += ' navbar-right';
3551 cfg.cls += ' navbar-left';
3555 if (this.align === 'right') {
3556 cfg.cls += ' navbar-right';
3560 cfg.cls += ' navbar-inverse';
3568 * sets the active Navigation item
3569 * @param {Roo.bootstrap.NavItem} the new current navitem
3571 setActiveItem : function(item)
3574 Roo.each(this.navItems, function(v){
3579 v.setActive(false, true);
3586 item.setActive(true, true);
3587 this.fireEvent('changed', this, item, prev);
3592 * gets the active Navigation item
3593 * @return {Roo.bootstrap.NavItem} the current navitem
3595 getActive : function()
3599 Roo.each(this.navItems, function(v){
3610 indexOfNav : function()
3614 Roo.each(this.navItems, function(v,i){
3625 * adds a Navigation item
3626 * @param {Roo.bootstrap.NavItem} the navitem to add
3628 addItem : function(cfg)
3630 var cn = new Roo.bootstrap.NavItem(cfg);
3632 cn.parentId = this.id;
3633 cn.onRender(this.el, null);
3637 * register a Navigation item
3638 * @param {Roo.bootstrap.NavItem} the navitem to add
3640 register : function(item)
3642 this.navItems.push( item);
3643 item.navId = this.navId;
3648 * clear all the Navigation item
3651 clearAll : function()
3654 this.el.dom.innerHTML = '';
3657 getNavItem: function(tabId)
3660 Roo.each(this.navItems, function(e) {
3661 if (e.tabId == tabId) {
3671 setActiveNext : function()
3673 var i = this.indexOfNav(this.getActive());
3674 if (i > this.navItems.length) {
3677 this.setActiveItem(this.navItems[i+1]);
3679 setActivePrev : function()
3681 var i = this.indexOfNav(this.getActive());
3685 this.setActiveItem(this.navItems[i-1]);
3687 clearWasActive : function(except) {
3688 Roo.each(this.navItems, function(e) {
3689 if (e.tabId != except.tabId && e.was_active) {
3690 e.was_active = false;
3697 getWasActive : function ()
3700 Roo.each(this.navItems, function(e) {
3715 Roo.apply(Roo.bootstrap.NavGroup, {
3719 * register a Navigation Group
3720 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3722 register : function(navgrp)
3724 this.groups[navgrp.navId] = navgrp;
3728 * fetch a Navigation Group based on the navigation ID
3729 * @param {string} the navgroup to add
3730 * @returns {Roo.bootstrap.NavGroup} the navgroup
3732 get: function(navId) {
3733 if (typeof(this.groups[navId]) == 'undefined') {
3735 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3737 return this.groups[navId] ;
3752 * @class Roo.bootstrap.NavItem
3753 * @extends Roo.bootstrap.Component
3754 * Bootstrap Navbar.NavItem class
3755 * @cfg {String} href link to
3756 * @cfg {String} html content of button
3757 * @cfg {String} badge text inside badge
3758 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3759 * @cfg {String} glyphicon name of glyphicon
3760 * @cfg {String} icon name of font awesome icon
3761 * @cfg {Boolean} active Is item active
3762 * @cfg {Boolean} disabled Is item disabled
3764 * @cfg {Boolean} preventDefault (true | false) default false
3765 * @cfg {String} tabId the tab that this item activates.
3766 * @cfg {String} tagtype (a|span) render as a href or span?
3767 * @cfg {Boolean} animateRef (true|false) link to element default false
3770 * Create a new Navbar Item
3771 * @param {Object} config The config object
3773 Roo.bootstrap.NavItem = function(config){
3774 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3779 * The raw click event for the entire grid.
3780 * @param {Roo.EventObject} e
3785 * Fires when the active item active state changes
3786 * @param {Roo.bootstrap.NavItem} this
3787 * @param {boolean} state the new state
3793 * Fires when scroll to element
3794 * @param {Roo.bootstrap.NavItem} this
3795 * @param {Object} options
3796 * @param {Roo.EventObject} e
3804 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3812 preventDefault : false,
3819 getAutoCreate : function(){
3827 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3829 if (this.disabled) {
3830 cfg.cls += ' disabled';
3833 if (this.href || this.html || this.glyphicon || this.icon) {
3837 href : this.href || "#",
3838 html: this.html || ''
3843 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3846 if(this.glyphicon) {
3847 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3852 cfg.cn[0].html += " <span class='caret'></span>";
3856 if (this.badge !== '') {
3858 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3866 initEvents: function()
3868 if (typeof (this.menu) != 'undefined') {
3869 this.menu.parentType = this.xtype;
3870 this.menu.triggerEl = this.el;
3871 this.menu = this.addxtype(Roo.apply({}, this.menu));
3874 this.el.select('a',true).on('click', this.onClick, this);
3876 if(this.tagtype == 'span'){
3877 this.el.select('span',true).on('click', this.onClick, this);
3880 // at this point parent should be available..
3881 this.parent().register(this);
3884 onClick : function(e)
3887 this.preventDefault ||
3894 if (this.disabled) {
3898 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3899 if (tg && tg.transition) {
3900 Roo.log("waiting for the transitionend");
3906 //Roo.log("fire event clicked");
3907 if(this.fireEvent('click', this, e) === false){
3911 if(this.tagtype == 'span'){
3915 //Roo.log(this.href);
3916 var ael = this.el.select('a',true).first();
3919 if(ael && this.animateRef && this.href.indexOf('#') > -1){
3920 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
3921 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
3922 return; // ignore... - it's a 'hash' to another page.
3926 this.scrollToElement(e);
3930 var p = this.parent();
3932 if (['tabs','pills'].indexOf(p.type)!==-1) {
3933 if (typeof(p.setActiveItem) !== 'undefined') {
3934 p.setActiveItem(this);
3939 isActive: function () {
3942 setActive : function(state, fire, is_was_active)
3944 if (this.active && !state & this.navId) {
3945 this.was_active = true;
3946 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3948 nv.clearWasActive(this);
3952 this.active = state;
3955 this.el.removeClass('active');
3956 } else if (!this.el.hasClass('active')) {
3957 this.el.addClass('active');
3960 this.fireEvent('changed', this, state);
3963 // show a panel if it's registered and related..
3965 if (!this.navId || !this.tabId || !state || is_was_active) {
3969 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3973 var pan = tg.getPanelByName(this.tabId);
3977 // if we can not flip to new panel - go back to old nav highlight..
3978 if (false == tg.showPanel(pan)) {
3979 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3981 var onav = nv.getWasActive();
3983 onav.setActive(true, false, true);
3992 // this should not be here...
3993 setDisabled : function(state)
3995 this.disabled = state;
3997 this.el.removeClass('disabled');
3998 } else if (!this.el.hasClass('disabled')) {
3999 this.el.addClass('disabled');
4005 * Fetch the element to display the tooltip on.
4006 * @return {Roo.Element} defaults to this.el
4008 tooltipEl : function()
4010 return this.el.select('' + this.tagtype + '', true).first();
4013 scrollToElement : function(e)
4015 var c = document.body;
4017 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4023 var o = target.calcOffsetsTo(c);
4030 this.fireEvent('scrollto', this, options, e);
4032 Roo.get(c).scrollTo('top', options.value, true);
4045 * <span> icon </span>
4046 * <span> text </span>
4047 * <span>badge </span>
4051 * @class Roo.bootstrap.NavSidebarItem
4052 * @extends Roo.bootstrap.NavItem
4053 * Bootstrap Navbar.NavSidebarItem class
4055 * Create a new Navbar Button
4056 * @param {Object} config The config object
4058 Roo.bootstrap.NavSidebarItem = function(config){
4059 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4064 * The raw click event for the entire grid.
4065 * @param {Roo.EventObject} e
4070 * Fires when the active item active state changes
4071 * @param {Roo.bootstrap.NavSidebarItem} this
4072 * @param {boolean} state the new state
4080 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4083 getAutoCreate : function(){
4088 href : this.href || '#',
4100 html : this.html || ''
4105 cfg.cls += ' active';
4109 if (this.glyphicon || this.icon) {
4110 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4111 a.cn.push({ tag : 'i', cls : c }) ;
4116 if (this.badge !== '') {
4117 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4121 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4122 a.cls += 'dropdown-toggle treeview' ;
4146 * @class Roo.bootstrap.Row
4147 * @extends Roo.bootstrap.Component
4148 * Bootstrap Row class (contains columns...)
4152 * @param {Object} config The config object
4155 Roo.bootstrap.Row = function(config){
4156 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4159 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4161 getAutoCreate : function(){
4180 * @class Roo.bootstrap.Element
4181 * @extends Roo.bootstrap.Component
4182 * Bootstrap Element class
4183 * @cfg {String} html contents of the element
4184 * @cfg {String} tag tag of the element
4185 * @cfg {String} cls class of the element
4186 * @cfg {Boolean} preventDefault (true|false) default false
4187 * @cfg {Boolean} clickable (true|false) default false
4190 * Create a new Element
4191 * @param {Object} config The config object
4194 Roo.bootstrap.Element = function(config){
4195 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4201 * When a element is chick
4202 * @param {Roo.bootstrap.Element} this
4203 * @param {Roo.EventObject} e
4209 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4214 preventDefault: false,
4217 getAutoCreate : function(){
4228 initEvents: function()
4230 Roo.bootstrap.Element.superclass.initEvents.call(this);
4233 this.el.on('click', this.onClick, this);
4238 onClick : function(e)
4240 if(this.preventDefault){
4244 this.fireEvent('click', this, e);
4247 getValue : function()
4249 return this.el.dom.innerHTML;
4252 setValue : function(value)
4254 this.el.dom.innerHTML = value;
4269 * @class Roo.bootstrap.Pagination
4270 * @extends Roo.bootstrap.Component
4271 * Bootstrap Pagination class
4272 * @cfg {String} size xs | sm | md | lg
4273 * @cfg {Boolean} inverse false | true
4276 * Create a new Pagination
4277 * @param {Object} config The config object
4280 Roo.bootstrap.Pagination = function(config){
4281 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4284 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4290 getAutoCreate : function(){
4296 cfg.cls += ' inverse';
4302 cfg.cls += " " + this.cls;
4320 * @class Roo.bootstrap.PaginationItem
4321 * @extends Roo.bootstrap.Component
4322 * Bootstrap PaginationItem class
4323 * @cfg {String} html text
4324 * @cfg {String} href the link
4325 * @cfg {Boolean} preventDefault (true | false) default true
4326 * @cfg {Boolean} active (true | false) default false
4327 * @cfg {Boolean} disabled default false
4331 * Create a new PaginationItem
4332 * @param {Object} config The config object
4336 Roo.bootstrap.PaginationItem = function(config){
4337 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4342 * The raw click event for the entire grid.
4343 * @param {Roo.EventObject} e
4349 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4353 preventDefault: true,
4358 getAutoCreate : function(){
4364 href : this.href ? this.href : '#',
4365 html : this.html ? this.html : ''
4375 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4379 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4385 initEvents: function() {
4387 this.el.on('click', this.onClick, this);
4390 onClick : function(e)
4392 Roo.log('PaginationItem on click ');
4393 if(this.preventDefault){
4401 this.fireEvent('click', this, e);
4417 * @class Roo.bootstrap.Slider
4418 * @extends Roo.bootstrap.Component
4419 * Bootstrap Slider class
4422 * Create a new Slider
4423 * @param {Object} config The config object
4426 Roo.bootstrap.Slider = function(config){
4427 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4430 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4432 getAutoCreate : function(){
4436 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4440 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4452 * Ext JS Library 1.1.1
4453 * Copyright(c) 2006-2007, Ext JS, LLC.
4455 * Originally Released Under LGPL - original licence link has changed is not relivant.
4458 * <script type="text/javascript">
4463 * @class Roo.grid.ColumnModel
4464 * @extends Roo.util.Observable
4465 * This is the default implementation of a ColumnModel used by the Grid. It defines
4466 * the columns in the grid.
4469 var colModel = new Roo.grid.ColumnModel([
4470 {header: "Ticker", width: 60, sortable: true, locked: true},
4471 {header: "Company Name", width: 150, sortable: true},
4472 {header: "Market Cap.", width: 100, sortable: true},
4473 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4474 {header: "Employees", width: 100, sortable: true, resizable: false}
4479 * The config options listed for this class are options which may appear in each
4480 * individual column definition.
4481 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4483 * @param {Object} config An Array of column config objects. See this class's
4484 * config objects for details.
4486 Roo.grid.ColumnModel = function(config){
4488 * The config passed into the constructor
4490 this.config = config;
4493 // if no id, create one
4494 // if the column does not have a dataIndex mapping,
4495 // map it to the order it is in the config
4496 for(var i = 0, len = config.length; i < len; i++){
4498 if(typeof c.dataIndex == "undefined"){
4501 if(typeof c.renderer == "string"){
4502 c.renderer = Roo.util.Format[c.renderer];
4504 if(typeof c.id == "undefined"){
4507 if(c.editor && c.editor.xtype){
4508 c.editor = Roo.factory(c.editor, Roo.grid);
4510 if(c.editor && c.editor.isFormField){
4511 c.editor = new Roo.grid.GridEditor(c.editor);
4513 this.lookup[c.id] = c;
4517 * The width of columns which have no width specified (defaults to 100)
4520 this.defaultWidth = 100;
4523 * Default sortable of columns which have no sortable specified (defaults to false)
4526 this.defaultSortable = false;
4530 * @event widthchange
4531 * Fires when the width of a column changes.
4532 * @param {ColumnModel} this
4533 * @param {Number} columnIndex The column index
4534 * @param {Number} newWidth The new width
4536 "widthchange": true,
4538 * @event headerchange
4539 * Fires when the text of a header changes.
4540 * @param {ColumnModel} this
4541 * @param {Number} columnIndex The column index
4542 * @param {Number} newText The new header text
4544 "headerchange": true,
4546 * @event hiddenchange
4547 * Fires when a column is hidden or "unhidden".
4548 * @param {ColumnModel} this
4549 * @param {Number} columnIndex The column index
4550 * @param {Boolean} hidden true if hidden, false otherwise
4552 "hiddenchange": true,
4554 * @event columnmoved
4555 * Fires when a column is moved.
4556 * @param {ColumnModel} this
4557 * @param {Number} oldIndex
4558 * @param {Number} newIndex
4560 "columnmoved" : true,
4562 * @event columlockchange
4563 * Fires when a column's locked state is changed
4564 * @param {ColumnModel} this
4565 * @param {Number} colIndex
4566 * @param {Boolean} locked true if locked
4568 "columnlockchange" : true
4570 Roo.grid.ColumnModel.superclass.constructor.call(this);
4572 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4574 * @cfg {String} header The header text to display in the Grid view.
4577 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4578 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4579 * specified, the column's index is used as an index into the Record's data Array.
4582 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4583 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4586 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4587 * Defaults to the value of the {@link #defaultSortable} property.
4588 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4591 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4594 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4597 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4600 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4603 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4604 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4605 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4606 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4609 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4612 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4615 * @cfg {String} cursor (Optional)
4618 * @cfg {String} tooltip (Optional)
4621 * Returns the id of the column at the specified index.
4622 * @param {Number} index The column index
4623 * @return {String} the id
4625 getColumnId : function(index){
4626 return this.config[index].id;
4630 * Returns the column for a specified id.
4631 * @param {String} id The column id
4632 * @return {Object} the column
4634 getColumnById : function(id){
4635 return this.lookup[id];
4640 * Returns the column for a specified dataIndex.
4641 * @param {String} dataIndex The column dataIndex
4642 * @return {Object|Boolean} the column or false if not found
4644 getColumnByDataIndex: function(dataIndex){
4645 var index = this.findColumnIndex(dataIndex);
4646 return index > -1 ? this.config[index] : false;
4650 * Returns the index for a specified column id.
4651 * @param {String} id The column id
4652 * @return {Number} the index, or -1 if not found
4654 getIndexById : function(id){
4655 for(var i = 0, len = this.config.length; i < len; i++){
4656 if(this.config[i].id == id){
4664 * Returns the index for a specified column dataIndex.
4665 * @param {String} dataIndex The column dataIndex
4666 * @return {Number} the index, or -1 if not found
4669 findColumnIndex : function(dataIndex){
4670 for(var i = 0, len = this.config.length; i < len; i++){
4671 if(this.config[i].dataIndex == dataIndex){
4679 moveColumn : function(oldIndex, newIndex){
4680 var c = this.config[oldIndex];
4681 this.config.splice(oldIndex, 1);
4682 this.config.splice(newIndex, 0, c);
4683 this.dataMap = null;
4684 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4687 isLocked : function(colIndex){
4688 return this.config[colIndex].locked === true;
4691 setLocked : function(colIndex, value, suppressEvent){
4692 if(this.isLocked(colIndex) == value){
4695 this.config[colIndex].locked = value;
4697 this.fireEvent("columnlockchange", this, colIndex, value);
4701 getTotalLockedWidth : function(){
4703 for(var i = 0; i < this.config.length; i++){
4704 if(this.isLocked(i) && !this.isHidden(i)){
4705 this.totalWidth += this.getColumnWidth(i);
4711 getLockedCount : function(){
4712 for(var i = 0, len = this.config.length; i < len; i++){
4713 if(!this.isLocked(i)){
4720 * Returns the number of columns.
4723 getColumnCount : function(visibleOnly){
4724 if(visibleOnly === true){
4726 for(var i = 0, len = this.config.length; i < len; i++){
4727 if(!this.isHidden(i)){
4733 return this.config.length;
4737 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4738 * @param {Function} fn
4739 * @param {Object} scope (optional)
4740 * @return {Array} result
4742 getColumnsBy : function(fn, scope){
4744 for(var i = 0, len = this.config.length; i < len; i++){
4745 var c = this.config[i];
4746 if(fn.call(scope||this, c, i) === true){
4754 * Returns true if the specified column is sortable.
4755 * @param {Number} col The column index
4758 isSortable : function(col){
4759 if(typeof this.config[col].sortable == "undefined"){
4760 return this.defaultSortable;
4762 return this.config[col].sortable;
4766 * Returns the rendering (formatting) function defined for the column.
4767 * @param {Number} col The column index.
4768 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4770 getRenderer : function(col){
4771 if(!this.config[col].renderer){
4772 return Roo.grid.ColumnModel.defaultRenderer;
4774 return this.config[col].renderer;
4778 * Sets the rendering (formatting) function for a column.
4779 * @param {Number} col The column index
4780 * @param {Function} fn The function to use to process the cell's raw data
4781 * to return HTML markup for the grid view. The render function is called with
4782 * the following parameters:<ul>
4783 * <li>Data value.</li>
4784 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4785 * <li>css A CSS style string to apply to the table cell.</li>
4786 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4787 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4788 * <li>Row index</li>
4789 * <li>Column index</li>
4790 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4792 setRenderer : function(col, fn){
4793 this.config[col].renderer = fn;
4797 * Returns the width for the specified column.
4798 * @param {Number} col The column index
4801 getColumnWidth : function(col){
4802 return this.config[col].width * 1 || this.defaultWidth;
4806 * Sets the width for a column.
4807 * @param {Number} col The column index
4808 * @param {Number} width The new width
4810 setColumnWidth : function(col, width, suppressEvent){
4811 this.config[col].width = width;
4812 this.totalWidth = null;
4814 this.fireEvent("widthchange", this, col, width);
4819 * Returns the total width of all columns.
4820 * @param {Boolean} includeHidden True to include hidden column widths
4823 getTotalWidth : function(includeHidden){
4824 if(!this.totalWidth){
4825 this.totalWidth = 0;
4826 for(var i = 0, len = this.config.length; i < len; i++){
4827 if(includeHidden || !this.isHidden(i)){
4828 this.totalWidth += this.getColumnWidth(i);
4832 return this.totalWidth;
4836 * Returns the header for the specified column.
4837 * @param {Number} col The column index
4840 getColumnHeader : function(col){
4841 return this.config[col].header;
4845 * Sets the header for a column.
4846 * @param {Number} col The column index
4847 * @param {String} header The new header
4849 setColumnHeader : function(col, header){
4850 this.config[col].header = header;
4851 this.fireEvent("headerchange", this, col, header);
4855 * Returns the tooltip for the specified column.
4856 * @param {Number} col The column index
4859 getColumnTooltip : function(col){
4860 return this.config[col].tooltip;
4863 * Sets the tooltip for a column.
4864 * @param {Number} col The column index
4865 * @param {String} tooltip The new tooltip
4867 setColumnTooltip : function(col, tooltip){
4868 this.config[col].tooltip = tooltip;
4872 * Returns the dataIndex for the specified column.
4873 * @param {Number} col The column index
4876 getDataIndex : function(col){
4877 return this.config[col].dataIndex;
4881 * Sets the dataIndex for a column.
4882 * @param {Number} col The column index
4883 * @param {Number} dataIndex The new dataIndex
4885 setDataIndex : function(col, dataIndex){
4886 this.config[col].dataIndex = dataIndex;
4892 * Returns true if the cell is editable.
4893 * @param {Number} colIndex The column index
4894 * @param {Number} rowIndex The row index
4897 isCellEditable : function(colIndex, rowIndex){
4898 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4902 * Returns the editor defined for the cell/column.
4903 * return false or null to disable editing.
4904 * @param {Number} colIndex The column index
4905 * @param {Number} rowIndex The row index
4908 getCellEditor : function(colIndex, rowIndex){
4909 return this.config[colIndex].editor;
4913 * Sets if a column is editable.
4914 * @param {Number} col The column index
4915 * @param {Boolean} editable True if the column is editable
4917 setEditable : function(col, editable){
4918 this.config[col].editable = editable;
4923 * Returns true if the column is hidden.
4924 * @param {Number} colIndex The column index
4927 isHidden : function(colIndex){
4928 return this.config[colIndex].hidden;
4933 * Returns true if the column width cannot be changed
4935 isFixed : function(colIndex){
4936 return this.config[colIndex].fixed;
4940 * Returns true if the column can be resized
4943 isResizable : function(colIndex){
4944 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4947 * Sets if a column is hidden.
4948 * @param {Number} colIndex The column index
4949 * @param {Boolean} hidden True if the column is hidden
4951 setHidden : function(colIndex, hidden){
4952 this.config[colIndex].hidden = hidden;
4953 this.totalWidth = null;
4954 this.fireEvent("hiddenchange", this, colIndex, hidden);
4958 * Sets the editor for a column.
4959 * @param {Number} col The column index
4960 * @param {Object} editor The editor object
4962 setEditor : function(col, editor){
4963 this.config[col].editor = editor;
4967 Roo.grid.ColumnModel.defaultRenderer = function(value){
4968 if(typeof value == "string" && value.length < 1){
4974 // Alias for backwards compatibility
4975 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4978 * Ext JS Library 1.1.1
4979 * Copyright(c) 2006-2007, Ext JS, LLC.
4981 * Originally Released Under LGPL - original licence link has changed is not relivant.
4984 * <script type="text/javascript">
4988 * @class Roo.LoadMask
4989 * A simple utility class for generically masking elements while loading data. If the element being masked has
4990 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4991 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4992 * element's UpdateManager load indicator and will be destroyed after the initial load.
4994 * Create a new LoadMask
4995 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4996 * @param {Object} config The config object
4998 Roo.LoadMask = function(el, config){
4999 this.el = Roo.get(el);
5000 Roo.apply(this, config);
5002 this.store.on('beforeload', this.onBeforeLoad, this);
5003 this.store.on('load', this.onLoad, this);
5004 this.store.on('loadexception', this.onLoadException, this);
5005 this.removeMask = false;
5007 var um = this.el.getUpdateManager();
5008 um.showLoadIndicator = false; // disable the default indicator
5009 um.on('beforeupdate', this.onBeforeLoad, this);
5010 um.on('update', this.onLoad, this);
5011 um.on('failure', this.onLoad, this);
5012 this.removeMask = true;
5016 Roo.LoadMask.prototype = {
5018 * @cfg {Boolean} removeMask
5019 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5020 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5024 * The text to display in a centered loading message box (defaults to 'Loading...')
5028 * @cfg {String} msgCls
5029 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5031 msgCls : 'x-mask-loading',
5034 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5040 * Disables the mask to prevent it from being displayed
5042 disable : function(){
5043 this.disabled = true;
5047 * Enables the mask so that it can be displayed
5049 enable : function(){
5050 this.disabled = false;
5053 onLoadException : function()
5057 if (typeof(arguments[3]) != 'undefined') {
5058 Roo.MessageBox.alert("Error loading",arguments[3]);
5062 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5063 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5072 this.el.unmask(this.removeMask);
5077 this.el.unmask(this.removeMask);
5081 onBeforeLoad : function(){
5083 this.el.mask(this.msg, this.msgCls);
5088 destroy : function(){
5090 this.store.un('beforeload', this.onBeforeLoad, this);
5091 this.store.un('load', this.onLoad, this);
5092 this.store.un('loadexception', this.onLoadException, this);
5094 var um = this.el.getUpdateManager();
5095 um.un('beforeupdate', this.onBeforeLoad, this);
5096 um.un('update', this.onLoad, this);
5097 um.un('failure', this.onLoad, this);
5108 * @class Roo.bootstrap.Table
5109 * @extends Roo.bootstrap.Component
5110 * Bootstrap Table class
5111 * @cfg {String} cls table class
5112 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5113 * @cfg {String} bgcolor Specifies the background color for a table
5114 * @cfg {Number} border Specifies whether the table cells should have borders or not
5115 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5116 * @cfg {Number} cellspacing Specifies the space between cells
5117 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5118 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5119 * @cfg {String} sortable Specifies that the table should be sortable
5120 * @cfg {String} summary Specifies a summary of the content of a table
5121 * @cfg {Number} width Specifies the width of a table
5122 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5124 * @cfg {boolean} striped Should the rows be alternative striped
5125 * @cfg {boolean} bordered Add borders to the table
5126 * @cfg {boolean} hover Add hover highlighting
5127 * @cfg {boolean} condensed Format condensed
5128 * @cfg {boolean} responsive Format condensed
5129 * @cfg {Boolean} loadMask (true|false) default false
5130 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5131 * @cfg {Boolean} thead (true|false) generate thead, default true
5132 * @cfg {Boolean} RowSelection (true|false) default false
5133 * @cfg {Boolean} CellSelection (true|false) default false
5134 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5138 * Create a new Table
5139 * @param {Object} config The config object
5142 Roo.bootstrap.Table = function(config){
5143 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5146 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5147 this.sm = this.selModel;
5148 this.sm.xmodule = this.xmodule || false;
5150 if (this.cm && typeof(this.cm.config) == 'undefined') {
5151 this.colModel = new Roo.grid.ColumnModel(this.cm);
5152 this.cm = this.colModel;
5153 this.cm.xmodule = this.xmodule || false;
5156 this.store= Roo.factory(this.store, Roo.data);
5157 this.ds = this.store;
5158 this.ds.xmodule = this.xmodule || false;
5161 if (this.footer && this.store) {
5162 this.footer.dataSource = this.ds;
5163 this.footer = Roo.factory(this.footer);
5170 * Fires when a cell is clicked
5171 * @param {Roo.bootstrap.Table} this
5172 * @param {Roo.Element} el
5173 * @param {Number} rowIndex
5174 * @param {Number} columnIndex
5175 * @param {Roo.EventObject} e
5179 * @event celldblclick
5180 * Fires when a cell is double clicked
5181 * @param {Roo.bootstrap.Table} this
5182 * @param {Roo.Element} el
5183 * @param {Number} rowIndex
5184 * @param {Number} columnIndex
5185 * @param {Roo.EventObject} e
5187 "celldblclick" : true,
5190 * Fires when a row is clicked
5191 * @param {Roo.bootstrap.Table} this
5192 * @param {Roo.Element} el
5193 * @param {Number} rowIndex
5194 * @param {Roo.EventObject} e
5198 * @event rowdblclick
5199 * Fires when a row is double clicked
5200 * @param {Roo.bootstrap.Table} this
5201 * @param {Roo.Element} el
5202 * @param {Number} rowIndex
5203 * @param {Roo.EventObject} e
5205 "rowdblclick" : true,
5208 * Fires when a mouseover occur
5209 * @param {Roo.bootstrap.Table} this
5210 * @param {Roo.Element} el
5211 * @param {Number} rowIndex
5212 * @param {Number} columnIndex
5213 * @param {Roo.EventObject} e
5218 * Fires when a mouseout occur
5219 * @param {Roo.bootstrap.Table} this
5220 * @param {Roo.Element} el
5221 * @param {Number} rowIndex
5222 * @param {Number} columnIndex
5223 * @param {Roo.EventObject} e
5228 * Fires when a row is rendered, so you can change add a style to it.
5229 * @param {Roo.bootstrap.Table} this
5230 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5234 * @event rowsrendered
5235 * Fires when all the rows have been rendered
5236 * @param {Roo.bootstrap.Table} this
5238 'rowsrendered' : true
5243 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5267 RowSelection : false,
5268 CellSelection : false,
5271 // Roo.Element - the tbody
5274 getAutoCreate : function(){
5275 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5284 cfg.cls += ' table-striped';
5288 cfg.cls += ' table-hover';
5290 if (this.bordered) {
5291 cfg.cls += ' table-bordered';
5293 if (this.condensed) {
5294 cfg.cls += ' table-condensed';
5296 if (this.responsive) {
5297 cfg.cls += ' table-responsive';
5301 cfg.cls+= ' ' +this.cls;
5304 // this lot should be simplifed...
5307 cfg.align=this.align;
5310 cfg.bgcolor=this.bgcolor;
5313 cfg.border=this.border;
5315 if (this.cellpadding) {
5316 cfg.cellpadding=this.cellpadding;
5318 if (this.cellspacing) {
5319 cfg.cellspacing=this.cellspacing;
5322 cfg.frame=this.frame;
5325 cfg.rules=this.rules;
5327 if (this.sortable) {
5328 cfg.sortable=this.sortable;
5331 cfg.summary=this.summary;
5334 cfg.width=this.width;
5337 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5340 if(this.store || this.cm){
5342 cfg.cn.push(this.renderHeader());
5345 cfg.cn.push(this.renderBody());
5348 cfg.cn.push(this.renderFooter());
5351 cfg.cls+= ' TableGrid';
5354 return { cn : [ cfg ] };
5357 initEvents : function()
5359 if(!this.store || !this.cm){
5363 //Roo.log('initEvents with ds!!!!');
5365 this.mainBody = this.el.select('tbody', true).first();
5370 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5371 e.on('click', _this.sort, _this);
5374 this.el.on("click", this.onClick, this);
5375 this.el.on("dblclick", this.onDblClick, this);
5377 // why is this done????? = it breaks dialogs??
5378 //this.parent().el.setStyle('position', 'relative');
5382 this.footer.parentId = this.id;
5383 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5386 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5388 this.store.on('load', this.onLoad, this);
5389 this.store.on('beforeload', this.onBeforeLoad, this);
5390 this.store.on('update', this.onUpdate, this);
5391 this.store.on('add', this.onAdd, this);
5395 onMouseover : function(e, el)
5397 var cell = Roo.get(el);
5403 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5404 cell = cell.findParent('td', false, true);
5407 var row = cell.findParent('tr', false, true);
5408 var cellIndex = cell.dom.cellIndex;
5409 var rowIndex = row.dom.rowIndex - 1; // start from 0
5411 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5415 onMouseout : function(e, el)
5417 var cell = Roo.get(el);
5423 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5424 cell = cell.findParent('td', false, true);
5427 var row = cell.findParent('tr', false, true);
5428 var cellIndex = cell.dom.cellIndex;
5429 var rowIndex = row.dom.rowIndex - 1; // start from 0
5431 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5435 onClick : function(e, el)
5437 var cell = Roo.get(el);
5439 if(!cell || (!this.CellSelection && !this.RowSelection)){
5443 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5444 cell = cell.findParent('td', false, true);
5447 if(!cell || typeof(cell) == 'undefined'){
5451 var row = cell.findParent('tr', false, true);
5453 if(!row || typeof(row) == 'undefined'){
5457 var cellIndex = cell.dom.cellIndex;
5458 var rowIndex = this.getRowIndex(row);
5460 if(this.CellSelection){
5461 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5464 if(this.RowSelection){
5465 this.fireEvent('rowclick', this, row, rowIndex, e);
5471 onDblClick : function(e,el)
5473 var cell = Roo.get(el);
5475 if(!cell || (!this.CellSelection && !this.RowSelection)){
5479 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5480 cell = cell.findParent('td', false, true);
5483 if(!cell || typeof(cell) == 'undefined'){
5487 var row = cell.findParent('tr', false, true);
5489 if(!row || typeof(row) == 'undefined'){
5493 var cellIndex = cell.dom.cellIndex;
5494 var rowIndex = this.getRowIndex(row);
5496 if(this.CellSelection){
5497 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5500 if(this.RowSelection){
5501 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5505 sort : function(e,el)
5507 var col = Roo.get(el);
5509 if(!col.hasClass('sortable')){
5513 var sort = col.attr('sort');
5516 if(col.hasClass('glyphicon-arrow-up')){
5520 this.store.sortInfo = {field : sort, direction : dir};
5523 Roo.log("calling footer first");
5524 this.footer.onClick('first');
5527 this.store.load({ params : { start : 0 } });
5531 renderHeader : function()
5540 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5542 var config = cm.config[i];
5547 html: cm.getColumnHeader(i)
5550 if(typeof(config.tooltip) != 'undefined'){
5551 c.tooltip = config.tooltip;
5554 if(typeof(config.colspan) != 'undefined'){
5555 c.colspan = config.colspan;
5558 if(typeof(config.hidden) != 'undefined' && config.hidden){
5559 c.style += ' display:none;';
5562 if(typeof(config.dataIndex) != 'undefined'){
5563 c.sort = config.dataIndex;
5566 if(typeof(config.sortable) != 'undefined' && config.sortable){
5570 if(typeof(config.align) != 'undefined' && config.align.length){
5571 c.style += ' text-align:' + config.align + ';';
5574 if(typeof(config.width) != 'undefined'){
5575 c.style += ' width:' + config.width + 'px;';
5578 if(typeof(config.cls) != 'undefined'){
5579 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5588 renderBody : function()
5598 colspan : this.cm.getColumnCount()
5608 renderFooter : function()
5618 colspan : this.cm.getColumnCount()
5632 Roo.log('ds onload');
5637 var ds = this.store;
5639 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5640 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5642 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5643 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5646 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5647 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5651 var tbody = this.mainBody;
5653 if(ds.getCount() > 0){
5654 ds.data.each(function(d,rowIndex){
5655 var row = this.renderRow(cm, ds, rowIndex);
5657 tbody.createChild(row);
5661 if(row.cellObjects.length){
5662 Roo.each(row.cellObjects, function(r){
5663 _this.renderCellObject(r);
5670 Roo.each(this.el.select('tbody td', true).elements, function(e){
5671 e.on('mouseover', _this.onMouseover, _this);
5674 Roo.each(this.el.select('tbody td', true).elements, function(e){
5675 e.on('mouseout', _this.onMouseout, _this);
5677 this.fireEvent('rowsrendered', this);
5678 //if(this.loadMask){
5679 // this.maskEl.hide();
5684 onUpdate : function(ds,record)
5686 this.refreshRow(record);
5689 onRemove : function(ds, record, index, isUpdate){
5690 if(isUpdate !== true){
5691 this.fireEvent("beforerowremoved", this, index, record);
5693 var bt = this.mainBody.dom;
5695 var rows = this.el.select('tbody > tr', true).elements;
5697 if(typeof(rows[index]) != 'undefined'){
5698 bt.removeChild(rows[index].dom);
5701 // if(bt.rows[index]){
5702 // bt.removeChild(bt.rows[index]);
5705 if(isUpdate !== true){
5706 //this.stripeRows(index);
5707 //this.syncRowHeights(index, index);
5709 this.fireEvent("rowremoved", this, index, record);
5713 onAdd : function(ds, records, rowIndex)
5715 //Roo.log('on Add called');
5716 // - note this does not handle multiple adding very well..
5717 var bt = this.mainBody.dom;
5718 for (var i =0 ; i < records.length;i++) {
5719 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5720 //Roo.log(records[i]);
5721 //Roo.log(this.store.getAt(rowIndex+i));
5722 this.insertRow(this.store, rowIndex + i, false);
5729 refreshRow : function(record){
5730 var ds = this.store, index;
5731 if(typeof record == 'number'){
5733 record = ds.getAt(index);
5735 index = ds.indexOf(record);
5737 this.insertRow(ds, index, true);
5738 this.onRemove(ds, record, index+1, true);
5739 //this.syncRowHeights(index, index);
5741 this.fireEvent("rowupdated", this, index, record);
5744 insertRow : function(dm, rowIndex, isUpdate){
5747 this.fireEvent("beforerowsinserted", this, rowIndex);
5749 //var s = this.getScrollState();
5750 var row = this.renderRow(this.cm, this.store, rowIndex);
5751 // insert before rowIndex..
5752 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5756 if(row.cellObjects.length){
5757 Roo.each(row.cellObjects, function(r){
5758 _this.renderCellObject(r);
5763 this.fireEvent("rowsinserted", this, rowIndex);
5764 //this.syncRowHeights(firstRow, lastRow);
5765 //this.stripeRows(firstRow);
5772 getRowDom : function(rowIndex)
5774 var rows = this.el.select('tbody > tr', true).elements;
5776 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5779 // returns the object tree for a tr..
5782 renderRow : function(cm, ds, rowIndex)
5785 var d = ds.getAt(rowIndex);
5792 var cellObjects = [];
5794 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5795 var config = cm.config[i];
5797 var renderer = cm.getRenderer(i);
5801 if(typeof(renderer) !== 'undefined'){
5802 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5804 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5805 // and are rendered into the cells after the row is rendered - using the id for the element.
5807 if(typeof(value) === 'object'){
5817 rowIndex : rowIndex,
5822 this.fireEvent('rowclass', this, rowcfg);
5826 cls : rowcfg.rowClass,
5828 html: (typeof(value) === 'object') ? '' : value
5835 if(typeof(config.colspan) != 'undefined'){
5836 td.colspan = config.colspan;
5839 if(typeof(config.hidden) != 'undefined' && config.hidden){
5840 td.style += ' display:none;';
5843 if(typeof(config.align) != 'undefined' && config.align.length){
5844 td.style += ' text-align:' + config.align + ';';
5847 if(typeof(config.width) != 'undefined'){
5848 td.style += ' width:' + config.width + 'px;';
5851 if(typeof(config.cursor) != 'undefined'){
5852 td.style += ' cursor:' + config.cursor + ';';
5855 if(typeof(config.cls) != 'undefined'){
5856 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
5863 row.cellObjects = cellObjects;
5871 onBeforeLoad : function()
5873 //Roo.log('ds onBeforeLoad');
5877 //if(this.loadMask){
5878 // this.maskEl.show();
5886 this.el.select('tbody', true).first().dom.innerHTML = '';
5889 * Show or hide a row.
5890 * @param {Number} rowIndex to show or hide
5891 * @param {Boolean} state hide
5893 setRowVisibility : function(rowIndex, state)
5895 var bt = this.mainBody.dom;
5897 var rows = this.el.select('tbody > tr', true).elements;
5899 if(typeof(rows[rowIndex]) == 'undefined'){
5902 rows[rowIndex].dom.style.display = state ? '' : 'none';
5906 getSelectionModel : function(){
5908 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5910 return this.selModel;
5913 * Render the Roo.bootstrap object from renderder
5915 renderCellObject : function(r)
5919 var t = r.cfg.render(r.container);
5922 Roo.each(r.cfg.cn, function(c){
5924 container: t.getChildContainer(),
5927 _this.renderCellObject(child);
5932 getRowIndex : function(row)
5936 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5959 * @class Roo.bootstrap.TableCell
5960 * @extends Roo.bootstrap.Component
5961 * Bootstrap TableCell class
5962 * @cfg {String} html cell contain text
5963 * @cfg {String} cls cell class
5964 * @cfg {String} tag cell tag (td|th) default td
5965 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5966 * @cfg {String} align Aligns the content in a cell
5967 * @cfg {String} axis Categorizes cells
5968 * @cfg {String} bgcolor Specifies the background color of a cell
5969 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5970 * @cfg {Number} colspan Specifies the number of columns a cell should span
5971 * @cfg {String} headers Specifies one or more header cells a cell is related to
5972 * @cfg {Number} height Sets the height of a cell
5973 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5974 * @cfg {Number} rowspan Sets the number of rows a cell should span
5975 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5976 * @cfg {String} valign Vertical aligns the content in a cell
5977 * @cfg {Number} width Specifies the width of a cell
5980 * Create a new TableCell
5981 * @param {Object} config The config object
5984 Roo.bootstrap.TableCell = function(config){
5985 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5988 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6008 getAutoCreate : function(){
6009 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6029 cfg.align=this.align
6035 cfg.bgcolor=this.bgcolor
6038 cfg.charoff=this.charoff
6041 cfg.colspan=this.colspan
6044 cfg.headers=this.headers
6047 cfg.height=this.height
6050 cfg.nowrap=this.nowrap
6053 cfg.rowspan=this.rowspan
6056 cfg.scope=this.scope
6059 cfg.valign=this.valign
6062 cfg.width=this.width
6081 * @class Roo.bootstrap.TableRow
6082 * @extends Roo.bootstrap.Component
6083 * Bootstrap TableRow class
6084 * @cfg {String} cls row class
6085 * @cfg {String} align Aligns the content in a table row
6086 * @cfg {String} bgcolor Specifies a background color for a table row
6087 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6088 * @cfg {String} valign Vertical aligns the content in a table row
6091 * Create a new TableRow
6092 * @param {Object} config The config object
6095 Roo.bootstrap.TableRow = function(config){
6096 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6099 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6107 getAutoCreate : function(){
6108 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6118 cfg.align = this.align;
6121 cfg.bgcolor = this.bgcolor;
6124 cfg.charoff = this.charoff;
6127 cfg.valign = this.valign;
6145 * @class Roo.bootstrap.TableBody
6146 * @extends Roo.bootstrap.Component
6147 * Bootstrap TableBody class
6148 * @cfg {String} cls element class
6149 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6150 * @cfg {String} align Aligns the content inside the element
6151 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6152 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6155 * Create a new TableBody
6156 * @param {Object} config The config object
6159 Roo.bootstrap.TableBody = function(config){
6160 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6163 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6171 getAutoCreate : function(){
6172 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6186 cfg.align = this.align;
6189 cfg.charoff = this.charoff;
6192 cfg.valign = this.valign;
6199 // initEvents : function()
6206 // this.store = Roo.factory(this.store, Roo.data);
6207 // this.store.on('load', this.onLoad, this);
6209 // this.store.load();
6213 // onLoad: function ()
6215 // this.fireEvent('load', this);
6225 * Ext JS Library 1.1.1
6226 * Copyright(c) 2006-2007, Ext JS, LLC.
6228 * Originally Released Under LGPL - original licence link has changed is not relivant.
6231 * <script type="text/javascript">
6234 // as we use this in bootstrap.
6235 Roo.namespace('Roo.form');
6237 * @class Roo.form.Action
6238 * Internal Class used to handle form actions
6240 * @param {Roo.form.BasicForm} el The form element or its id
6241 * @param {Object} config Configuration options
6246 // define the action interface
6247 Roo.form.Action = function(form, options){
6249 this.options = options || {};
6252 * Client Validation Failed
6255 Roo.form.Action.CLIENT_INVALID = 'client';
6257 * Server Validation Failed
6260 Roo.form.Action.SERVER_INVALID = 'server';
6262 * Connect to Server Failed
6265 Roo.form.Action.CONNECT_FAILURE = 'connect';
6267 * Reading Data from Server Failed
6270 Roo.form.Action.LOAD_FAILURE = 'load';
6272 Roo.form.Action.prototype = {
6274 failureType : undefined,
6275 response : undefined,
6279 run : function(options){
6284 success : function(response){
6289 handleResponse : function(response){
6293 // default connection failure
6294 failure : function(response){
6296 this.response = response;
6297 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6298 this.form.afterAction(this, false);
6301 processResponse : function(response){
6302 this.response = response;
6303 if(!response.responseText){
6306 this.result = this.handleResponse(response);
6310 // utility functions used internally
6311 getUrl : function(appendParams){
6312 var url = this.options.url || this.form.url || this.form.el.dom.action;
6314 var p = this.getParams();
6316 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6322 getMethod : function(){
6323 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6326 getParams : function(){
6327 var bp = this.form.baseParams;
6328 var p = this.options.params;
6330 if(typeof p == "object"){
6331 p = Roo.urlEncode(Roo.applyIf(p, bp));
6332 }else if(typeof p == 'string' && bp){
6333 p += '&' + Roo.urlEncode(bp);
6336 p = Roo.urlEncode(bp);
6341 createCallback : function(){
6343 success: this.success,
6344 failure: this.failure,
6346 timeout: (this.form.timeout*1000),
6347 upload: this.form.fileUpload ? this.success : undefined
6352 Roo.form.Action.Submit = function(form, options){
6353 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6356 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6359 haveProgress : false,
6360 uploadComplete : false,
6362 // uploadProgress indicator.
6363 uploadProgress : function()
6365 if (!this.form.progressUrl) {
6369 if (!this.haveProgress) {
6370 Roo.MessageBox.progress("Uploading", "Uploading");
6372 if (this.uploadComplete) {
6373 Roo.MessageBox.hide();
6377 this.haveProgress = true;
6379 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6381 var c = new Roo.data.Connection();
6383 url : this.form.progressUrl,
6388 success : function(req){
6389 //console.log(data);
6393 rdata = Roo.decode(req.responseText)
6395 Roo.log("Invalid data from server..");
6399 if (!rdata || !rdata.success) {
6401 Roo.MessageBox.alert(Roo.encode(rdata));
6404 var data = rdata.data;
6406 if (this.uploadComplete) {
6407 Roo.MessageBox.hide();
6412 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6413 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6416 this.uploadProgress.defer(2000,this);
6419 failure: function(data) {
6420 Roo.log('progress url failed ');
6431 // run get Values on the form, so it syncs any secondary forms.
6432 this.form.getValues();
6434 var o = this.options;
6435 var method = this.getMethod();
6436 var isPost = method == 'POST';
6437 if(o.clientValidation === false || this.form.isValid()){
6439 if (this.form.progressUrl) {
6440 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6441 (new Date() * 1) + '' + Math.random());
6446 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6447 form:this.form.el.dom,
6448 url:this.getUrl(!isPost),
6450 params:isPost ? this.getParams() : null,
6451 isUpload: this.form.fileUpload
6454 this.uploadProgress();
6456 }else if (o.clientValidation !== false){ // client validation failed
6457 this.failureType = Roo.form.Action.CLIENT_INVALID;
6458 this.form.afterAction(this, false);
6462 success : function(response)
6464 this.uploadComplete= true;
6465 if (this.haveProgress) {
6466 Roo.MessageBox.hide();
6470 var result = this.processResponse(response);
6471 if(result === true || result.success){
6472 this.form.afterAction(this, true);
6476 this.form.markInvalid(result.errors);
6477 this.failureType = Roo.form.Action.SERVER_INVALID;
6479 this.form.afterAction(this, false);
6481 failure : function(response)
6483 this.uploadComplete= true;
6484 if (this.haveProgress) {
6485 Roo.MessageBox.hide();
6488 this.response = response;
6489 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6490 this.form.afterAction(this, false);
6493 handleResponse : function(response){
6494 if(this.form.errorReader){
6495 var rs = this.form.errorReader.read(response);
6498 for(var i = 0, len = rs.records.length; i < len; i++) {
6499 var r = rs.records[i];
6503 if(errors.length < 1){
6507 success : rs.success,
6513 ret = Roo.decode(response.responseText);
6517 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6527 Roo.form.Action.Load = function(form, options){
6528 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6529 this.reader = this.form.reader;
6532 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6537 Roo.Ajax.request(Roo.apply(
6538 this.createCallback(), {
6539 method:this.getMethod(),
6540 url:this.getUrl(false),
6541 params:this.getParams()
6545 success : function(response){
6547 var result = this.processResponse(response);
6548 if(result === true || !result.success || !result.data){
6549 this.failureType = Roo.form.Action.LOAD_FAILURE;
6550 this.form.afterAction(this, false);
6553 this.form.clearInvalid();
6554 this.form.setValues(result.data);
6555 this.form.afterAction(this, true);
6558 handleResponse : function(response){
6559 if(this.form.reader){
6560 var rs = this.form.reader.read(response);
6561 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6563 success : rs.success,
6567 return Roo.decode(response.responseText);
6571 Roo.form.Action.ACTION_TYPES = {
6572 'load' : Roo.form.Action.Load,
6573 'submit' : Roo.form.Action.Submit
6582 * @class Roo.bootstrap.Form
6583 * @extends Roo.bootstrap.Component
6584 * Bootstrap Form class
6585 * @cfg {String} method GET | POST (default POST)
6586 * @cfg {String} labelAlign top | left (default top)
6587 * @cfg {String} align left | right - for navbars
6588 * @cfg {Boolean} loadMask load mask when submit (default true)
6593 * @param {Object} config The config object
6597 Roo.bootstrap.Form = function(config){
6598 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6601 * @event clientvalidation
6602 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6603 * @param {Form} this
6604 * @param {Boolean} valid true if the form has passed client-side validation
6606 clientvalidation: true,
6608 * @event beforeaction
6609 * Fires before any action is performed. Return false to cancel the action.
6610 * @param {Form} this
6611 * @param {Action} action The action to be performed
6615 * @event actionfailed
6616 * Fires when an action fails.
6617 * @param {Form} this
6618 * @param {Action} action The action that failed
6620 actionfailed : true,
6622 * @event actioncomplete
6623 * Fires when an action is completed.
6624 * @param {Form} this
6625 * @param {Action} action The action that completed
6627 actioncomplete : true
6632 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6635 * @cfg {String} method
6636 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6641 * The URL to use for form actions if one isn't supplied in the action options.
6644 * @cfg {Boolean} fileUpload
6645 * Set to true if this form is a file upload.
6649 * @cfg {Object} baseParams
6650 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6654 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6658 * @cfg {Sting} align (left|right) for navbar forms
6663 activeAction : null,
6666 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6667 * element by passing it or its id or mask the form itself by passing in true.
6670 waitMsgTarget : false,
6674 getAutoCreate : function(){
6678 method : this.method || 'POST',
6679 id : this.id || Roo.id(),
6682 if (this.parent().xtype.match(/^Nav/)) {
6683 cfg.cls = 'navbar-form navbar-' + this.align;
6687 if (this.labelAlign == 'left' ) {
6688 cfg.cls += ' form-horizontal';
6694 initEvents : function()
6696 this.el.on('submit', this.onSubmit, this);
6697 // this was added as random key presses on the form where triggering form submit.
6698 this.el.on('keypress', function(e) {
6699 if (e.getCharCode() != 13) {
6702 // we might need to allow it for textareas.. and some other items.
6703 // check e.getTarget().
6705 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6709 Roo.log("keypress blocked");
6717 onSubmit : function(e){
6722 * Returns true if client-side validation on the form is successful.
6725 isValid : function(){
6726 var items = this.getItems();
6728 items.each(function(f){
6737 * Returns true if any fields in this form have changed since their original load.
6740 isDirty : function(){
6742 var items = this.getItems();
6743 items.each(function(f){
6753 * Performs a predefined action (submit or load) or custom actions you define on this form.
6754 * @param {String} actionName The name of the action type
6755 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6756 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6757 * accept other config options):
6759 Property Type Description
6760 ---------------- --------------- ----------------------------------------------------------------------------------
6761 url String The url for the action (defaults to the form's url)
6762 method String The form method to use (defaults to the form's method, or POST if not defined)
6763 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6764 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6765 validate the form on the client (defaults to false)
6767 * @return {BasicForm} this
6769 doAction : function(action, options){
6770 if(typeof action == 'string'){
6771 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6773 if(this.fireEvent('beforeaction', this, action) !== false){
6774 this.beforeAction(action);
6775 action.run.defer(100, action);
6781 beforeAction : function(action){
6782 var o = action.options;
6785 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6787 // not really supported yet.. ??
6789 //if(this.waitMsgTarget === true){
6790 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6791 //}else if(this.waitMsgTarget){
6792 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6793 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6795 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6801 afterAction : function(action, success){
6802 this.activeAction = null;
6803 var o = action.options;
6805 //if(this.waitMsgTarget === true){
6807 //}else if(this.waitMsgTarget){
6808 // this.waitMsgTarget.unmask();
6810 // Roo.MessageBox.updateProgress(1);
6811 // Roo.MessageBox.hide();
6818 Roo.callback(o.success, o.scope, [this, action]);
6819 this.fireEvent('actioncomplete', this, action);
6823 // failure condition..
6824 // we have a scenario where updates need confirming.
6825 // eg. if a locking scenario exists..
6826 // we look for { errors : { needs_confirm : true }} in the response.
6828 (typeof(action.result) != 'undefined') &&
6829 (typeof(action.result.errors) != 'undefined') &&
6830 (typeof(action.result.errors.needs_confirm) != 'undefined')
6833 Roo.log("not supported yet");
6836 Roo.MessageBox.confirm(
6837 "Change requires confirmation",
6838 action.result.errorMsg,
6843 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6853 Roo.callback(o.failure, o.scope, [this, action]);
6854 // show an error message if no failed handler is set..
6855 if (!this.hasListener('actionfailed')) {
6856 Roo.log("need to add dialog support");
6858 Roo.MessageBox.alert("Error",
6859 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6860 action.result.errorMsg :
6861 "Saving Failed, please check your entries or try again"
6866 this.fireEvent('actionfailed', this, action);
6871 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6872 * @param {String} id The value to search for
6875 findField : function(id){
6876 var items = this.getItems();
6877 var field = items.get(id);
6879 items.each(function(f){
6880 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6887 return field || null;
6890 * Mark fields in this form invalid in bulk.
6891 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6892 * @return {BasicForm} this
6894 markInvalid : function(errors){
6895 if(errors instanceof Array){
6896 for(var i = 0, len = errors.length; i < len; i++){
6897 var fieldError = errors[i];
6898 var f = this.findField(fieldError.id);
6900 f.markInvalid(fieldError.msg);
6906 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6907 field.markInvalid(errors[id]);
6911 //Roo.each(this.childForms || [], function (f) {
6912 // f.markInvalid(errors);
6919 * Set values for fields in this form in bulk.
6920 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6921 * @return {BasicForm} this
6923 setValues : function(values){
6924 if(values instanceof Array){ // array of objects
6925 for(var i = 0, len = values.length; i < len; i++){
6927 var f = this.findField(v.id);
6929 f.setValue(v.value);
6930 if(this.trackResetOnLoad){
6931 f.originalValue = f.getValue();
6935 }else{ // object hash
6938 if(typeof values[id] != 'function' && (field = this.findField(id))){
6940 if (field.setFromData &&
6942 field.displayField &&
6943 // combos' with local stores can
6944 // be queried via setValue()
6945 // to set their value..
6946 (field.store && !field.store.isLocal)
6950 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6951 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6952 field.setFromData(sd);
6955 field.setValue(values[id]);
6959 if(this.trackResetOnLoad){
6960 field.originalValue = field.getValue();
6966 //Roo.each(this.childForms || [], function (f) {
6967 // f.setValues(values);
6974 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6975 * they are returned as an array.
6976 * @param {Boolean} asString
6979 getValues : function(asString){
6980 //if (this.childForms) {
6981 // copy values from the child forms
6982 // Roo.each(this.childForms, function (f) {
6983 // this.setValues(f.getValues());
6989 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6990 if(asString === true){
6993 return Roo.urlDecode(fs);
6997 * Returns the fields in this form as an object with key/value pairs.
6998 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7001 getFieldValues : function(with_hidden)
7003 var items = this.getItems();
7005 items.each(function(f){
7009 var v = f.getValue();
7010 if (f.inputType =='radio') {
7011 if (typeof(ret[f.getName()]) == 'undefined') {
7012 ret[f.getName()] = ''; // empty..
7015 if (!f.el.dom.checked) {
7023 // not sure if this supported any more..
7024 if ((typeof(v) == 'object') && f.getRawValue) {
7025 v = f.getRawValue() ; // dates..
7027 // combo boxes where name != hiddenName...
7028 if (f.name != f.getName()) {
7029 ret[f.name] = f.getRawValue();
7031 ret[f.getName()] = v;
7038 * Clears all invalid messages in this form.
7039 * @return {BasicForm} this
7041 clearInvalid : function(){
7042 var items = this.getItems();
7044 items.each(function(f){
7055 * @return {BasicForm} this
7058 var items = this.getItems();
7059 items.each(function(f){
7063 Roo.each(this.childForms || [], function (f) {
7070 getItems : function()
7072 var r=new Roo.util.MixedCollection(false, function(o){
7073 return o.id || (o.id = Roo.id());
7075 var iter = function(el) {
7082 Roo.each(el.items,function(e) {
7102 * Ext JS Library 1.1.1
7103 * Copyright(c) 2006-2007, Ext JS, LLC.
7105 * Originally Released Under LGPL - original licence link has changed is not relivant.
7108 * <script type="text/javascript">
7111 * @class Roo.form.VTypes
7112 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7115 Roo.form.VTypes = function(){
7116 // closure these in so they are only created once.
7117 var alpha = /^[a-zA-Z_]+$/;
7118 var alphanum = /^[a-zA-Z0-9_]+$/;
7119 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7120 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7122 // All these messages and functions are configurable
7125 * The function used to validate email addresses
7126 * @param {String} value The email address
7128 'email' : function(v){
7129 return email.test(v);
7132 * The error text to display when the email validation function returns false
7135 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7137 * The keystroke filter mask to be applied on email input
7140 'emailMask' : /[a-z0-9_\.\-@]/i,
7143 * The function used to validate URLs
7144 * @param {String} value The URL
7146 'url' : function(v){
7150 * The error text to display when the url validation function returns false
7153 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7156 * The function used to validate alpha values
7157 * @param {String} value The value
7159 'alpha' : function(v){
7160 return alpha.test(v);
7163 * The error text to display when the alpha validation function returns false
7166 'alphaText' : 'This field should only contain letters and _',
7168 * The keystroke filter mask to be applied on alpha input
7171 'alphaMask' : /[a-z_]/i,
7174 * The function used to validate alphanumeric values
7175 * @param {String} value The value
7177 'alphanum' : function(v){
7178 return alphanum.test(v);
7181 * The error text to display when the alphanumeric validation function returns false
7184 'alphanumText' : 'This field should only contain letters, numbers and _',
7186 * The keystroke filter mask to be applied on alphanumeric input
7189 'alphanumMask' : /[a-z0-9_]/i
7199 * @class Roo.bootstrap.Input
7200 * @extends Roo.bootstrap.Component
7201 * Bootstrap Input class
7202 * @cfg {Boolean} disabled is it disabled
7203 * @cfg {String} fieldLabel - the label associated
7204 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7205 * @cfg {String} name name of the input
7206 * @cfg {string} fieldLabel - the label associated
7207 * @cfg {string} inputType - input / file submit ...
7208 * @cfg {string} placeholder - placeholder to put in text.
7209 * @cfg {string} before - input group add on before
7210 * @cfg {string} after - input group add on after
7211 * @cfg {string} size - (lg|sm) or leave empty..
7212 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7213 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7214 * @cfg {Number} md colspan out of 12 for computer-sized screens
7215 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7216 * @cfg {string} value default value of the input
7217 * @cfg {Number} labelWidth set the width of label (0-12)
7218 * @cfg {String} labelAlign (top|left)
7219 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7220 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7222 * @cfg {String} align (left|center|right) Default left
7227 * Create a new Input
7228 * @param {Object} config The config object
7231 Roo.bootstrap.Input = function(config){
7232 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7237 * Fires when this field receives input focus.
7238 * @param {Roo.form.Field} this
7243 * Fires when this field loses input focus.
7244 * @param {Roo.form.Field} this
7249 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7250 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7251 * @param {Roo.form.Field} this
7252 * @param {Roo.EventObject} e The event object
7257 * Fires just before the field blurs if the field value has changed.
7258 * @param {Roo.form.Field} this
7259 * @param {Mixed} newValue The new value
7260 * @param {Mixed} oldValue The original value
7265 * Fires after the field has been marked as invalid.
7266 * @param {Roo.form.Field} this
7267 * @param {String} msg The validation message
7272 * Fires after the field has been validated with no errors.
7273 * @param {Roo.form.Field} this
7278 * Fires after the key up
7279 * @param {Roo.form.Field} this
7280 * @param {Roo.EventObject} e The event Object
7286 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7288 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7289 automatic validation (defaults to "keyup").
7291 validationEvent : "keyup",
7293 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7295 validateOnBlur : true,
7297 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7299 validationDelay : 250,
7301 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7303 focusClass : "x-form-focus", // not needed???
7307 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7309 invalidClass : "has-warning",
7312 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7314 validClass : "has-success",
7317 * @cfg {Boolean} hasFeedback (true|false) default true
7322 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7324 invalidFeedbackClass : "glyphicon-warning-sign",
7327 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7329 validFeedbackClass : "glyphicon-ok",
7332 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7334 selectOnFocus : false,
7337 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7341 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7346 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7348 disableKeyFilter : false,
7351 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7355 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7359 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7361 blankText : "This field is required",
7364 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7368 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7370 maxLength : Number.MAX_VALUE,
7372 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7374 minLengthText : "The minimum length for this field is {0}",
7376 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7378 maxLengthText : "The maximum length for this field is {0}",
7382 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7383 * If available, this function will be called only after the basic validators all return true, and will be passed the
7384 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7388 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7389 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7390 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7394 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7398 autocomplete: false,
7417 formatedValue : false,
7419 parentLabelAlign : function()
7422 while (parent.parent()) {
7423 parent = parent.parent();
7424 if (typeof(parent.labelAlign) !='undefined') {
7425 return parent.labelAlign;
7432 getAutoCreate : function(){
7434 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7440 if(this.inputType != 'hidden'){
7441 cfg.cls = 'form-group' //input-group
7447 type : this.inputType,
7449 cls : 'form-control',
7450 placeholder : this.placeholder || '',
7451 autocomplete : this.autocomplete || 'new-password'
7456 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7459 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7460 input.maxLength = this.maxLength;
7463 if (this.disabled) {
7464 input.disabled=true;
7467 if (this.readOnly) {
7468 input.readonly=true;
7472 input.name = this.name;
7475 input.cls += ' input-' + this.size;
7478 ['xs','sm','md','lg'].map(function(size){
7479 if (settings[size]) {
7480 cfg.cls += ' col-' + size + '-' + settings[size];
7484 var inputblock = input;
7488 cls: 'glyphicon form-control-feedback'
7491 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7494 cls : 'has-feedback',
7502 if (this.before || this.after) {
7505 cls : 'input-group',
7509 if (this.before && typeof(this.before) == 'string') {
7511 inputblock.cn.push({
7513 cls : 'roo-input-before input-group-addon',
7517 if (this.before && typeof(this.before) == 'object') {
7518 this.before = Roo.factory(this.before);
7519 Roo.log(this.before);
7520 inputblock.cn.push({
7522 cls : 'roo-input-before input-group-' +
7523 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7527 inputblock.cn.push(input);
7529 if (this.after && typeof(this.after) == 'string') {
7530 inputblock.cn.push({
7532 cls : 'roo-input-after input-group-addon',
7536 if (this.after && typeof(this.after) == 'object') {
7537 this.after = Roo.factory(this.after);
7538 Roo.log(this.after);
7539 inputblock.cn.push({
7541 cls : 'roo-input-after input-group-' +
7542 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7546 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7547 inputblock.cls += ' has-feedback';
7548 inputblock.cn.push(feedback);
7552 if (align ==='left' && this.fieldLabel.length) {
7553 Roo.log("left and has label");
7559 cls : 'control-label col-sm-' + this.labelWidth,
7560 html : this.fieldLabel
7564 cls : "col-sm-" + (12 - this.labelWidth),
7571 } else if ( this.fieldLabel.length) {
7577 //cls : 'input-group-addon',
7578 html : this.fieldLabel
7588 Roo.log(" no label && no align");
7597 Roo.log('input-parentType: ' + this.parentType);
7599 if (this.parentType === 'Navbar' && this.parent().bar) {
7600 cfg.cls += ' navbar-form';
7608 * return the real input element.
7610 inputEl: function ()
7612 return this.el.select('input.form-control',true).first();
7615 tooltipEl : function()
7617 return this.inputEl();
7620 setDisabled : function(v)
7622 var i = this.inputEl().dom;
7624 i.removeAttribute('disabled');
7628 i.setAttribute('disabled','true');
7630 initEvents : function()
7633 this.inputEl().on("keydown" , this.fireKey, this);
7634 this.inputEl().on("focus", this.onFocus, this);
7635 this.inputEl().on("blur", this.onBlur, this);
7637 this.inputEl().relayEvent('keyup', this);
7639 // reference to original value for reset
7640 this.originalValue = this.getValue();
7641 //Roo.form.TextField.superclass.initEvents.call(this);
7642 if(this.validationEvent == 'keyup'){
7643 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7644 this.inputEl().on('keyup', this.filterValidation, this);
7646 else if(this.validationEvent !== false){
7647 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7650 if(this.selectOnFocus){
7651 this.on("focus", this.preFocus, this);
7654 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7655 this.inputEl().on("keypress", this.filterKeys, this);
7658 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7659 this.el.on("click", this.autoSize, this);
7662 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7663 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7666 if (typeof(this.before) == 'object') {
7667 this.before.render(this.el.select('.roo-input-before',true).first());
7669 if (typeof(this.after) == 'object') {
7670 this.after.render(this.el.select('.roo-input-after',true).first());
7675 filterValidation : function(e){
7676 if(!e.isNavKeyPress()){
7677 this.validationTask.delay(this.validationDelay);
7681 * Validates the field value
7682 * @return {Boolean} True if the value is valid, else false
7684 validate : function(){
7685 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7686 if(this.disabled || this.validateValue(this.getRawValue())){
7697 * Validates a value according to the field's validation rules and marks the field as invalid
7698 * if the validation fails
7699 * @param {Mixed} value The value to validate
7700 * @return {Boolean} True if the value is valid, else false
7702 validateValue : function(value){
7703 if(value.length < 1) { // if it's blank
7704 if(this.allowBlank){
7710 if(value.length < this.minLength){
7713 if(value.length > this.maxLength){
7717 var vt = Roo.form.VTypes;
7718 if(!vt[this.vtype](value, this)){
7722 if(typeof this.validator == "function"){
7723 var msg = this.validator(value);
7729 if(this.regex && !this.regex.test(value)){
7739 fireKey : function(e){
7740 //Roo.log('field ' + e.getKey());
7741 if(e.isNavKeyPress()){
7742 this.fireEvent("specialkey", this, e);
7745 focus : function (selectText){
7747 this.inputEl().focus();
7748 if(selectText === true){
7749 this.inputEl().dom.select();
7755 onFocus : function(){
7756 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7757 // this.el.addClass(this.focusClass);
7760 this.hasFocus = true;
7761 this.startValue = this.getValue();
7762 this.fireEvent("focus", this);
7766 beforeBlur : Roo.emptyFn,
7770 onBlur : function(){
7772 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7773 //this.el.removeClass(this.focusClass);
7775 this.hasFocus = false;
7776 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7779 var v = this.getValue();
7780 if(String(v) !== String(this.startValue)){
7781 this.fireEvent('change', this, v, this.startValue);
7783 this.fireEvent("blur", this);
7787 * Resets the current field value to the originally loaded value and clears any validation messages
7790 this.setValue(this.originalValue);
7794 * Returns the name of the field
7795 * @return {Mixed} name The name field
7797 getName: function(){
7801 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7802 * @return {Mixed} value The field value
7804 getValue : function(){
7806 var v = this.inputEl().getValue();
7811 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7812 * @return {Mixed} value The field value
7814 getRawValue : function(){
7815 var v = this.inputEl().getValue();
7821 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7822 * @param {Mixed} value The value to set
7824 setRawValue : function(v){
7825 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7828 selectText : function(start, end){
7829 var v = this.getRawValue();
7831 start = start === undefined ? 0 : start;
7832 end = end === undefined ? v.length : end;
7833 var d = this.inputEl().dom;
7834 if(d.setSelectionRange){
7835 d.setSelectionRange(start, end);
7836 }else if(d.createTextRange){
7837 var range = d.createTextRange();
7838 range.moveStart("character", start);
7839 range.moveEnd("character", v.length-end);
7846 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7847 * @param {Mixed} value The value to set
7849 setValue : function(v){
7852 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7858 processValue : function(value){
7859 if(this.stripCharsRe){
7860 var newValue = value.replace(this.stripCharsRe, '');
7861 if(newValue !== value){
7862 this.setRawValue(newValue);
7869 preFocus : function(){
7871 if(this.selectOnFocus){
7872 this.inputEl().dom.select();
7875 filterKeys : function(e){
7877 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7880 var c = e.getCharCode(), cc = String.fromCharCode(c);
7881 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7884 if(!this.maskRe.test(cc)){
7889 * Clear any invalid styles/messages for this field
7891 clearInvalid : function(){
7893 if(!this.el || this.preventMark){ // not rendered
7896 this.el.removeClass(this.invalidClass);
7898 this.fireEvent('valid', this);
7902 * Mark this field as valid
7904 markValid : function(){
7905 if(!this.el || this.preventMark){ // not rendered
7909 this.el.removeClass([this.invalidClass, this.validClass]);
7911 if(this.disabled || this.allowBlank){
7915 this.el.addClass(this.validClass);
7917 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7919 var feedback = this.el.select('.form-control-feedback', true).first();
7922 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7923 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7928 this.fireEvent('valid', this);
7932 * Mark this field as invalid
7933 * @param {String} msg The validation message
7935 markInvalid : function(msg){
7936 if(!this.el || this.preventMark){ // not rendered
7940 this.el.removeClass([this.invalidClass, this.validClass]);
7942 if(this.disabled || this.allowBlank){
7946 this.el.addClass(this.invalidClass);
7948 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7950 var feedback = this.el.select('.form-control-feedback', true).first();
7953 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7955 if(this.getValue().length){
7956 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7963 this.fireEvent('invalid', this, msg);
7966 SafariOnKeyDown : function(event)
7968 // this is a workaround for a password hang bug on chrome/ webkit.
7970 var isSelectAll = false;
7972 if(this.inputEl().dom.selectionEnd > 0){
7973 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7975 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7976 event.preventDefault();
7981 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7983 event.preventDefault();
7984 // this is very hacky as keydown always get's upper case.
7986 var cc = String.fromCharCode(event.getCharCode());
7987 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7991 adjustWidth : function(tag, w){
7992 tag = tag.toLowerCase();
7993 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7994 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7998 if(tag == 'textarea'){
8001 }else if(Roo.isOpera){
8005 if(tag == 'textarea'){
8024 * @class Roo.bootstrap.TextArea
8025 * @extends Roo.bootstrap.Input
8026 * Bootstrap TextArea class
8027 * @cfg {Number} cols Specifies the visible width of a text area
8028 * @cfg {Number} rows Specifies the visible number of lines in a text area
8029 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8030 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8031 * @cfg {string} html text
8034 * Create a new TextArea
8035 * @param {Object} config The config object
8038 Roo.bootstrap.TextArea = function(config){
8039 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8043 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8053 getAutoCreate : function(){
8055 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8066 value : this.value || '',
8067 html: this.html || '',
8068 cls : 'form-control',
8069 placeholder : this.placeholder || ''
8073 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8074 input.maxLength = this.maxLength;
8078 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8082 input.cols = this.cols;
8085 if (this.readOnly) {
8086 input.readonly = true;
8090 input.name = this.name;
8094 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8098 ['xs','sm','md','lg'].map(function(size){
8099 if (settings[size]) {
8100 cfg.cls += ' col-' + size + '-' + settings[size];
8104 var inputblock = input;
8106 if(this.hasFeedback && !this.allowBlank){
8110 cls: 'glyphicon form-control-feedback'
8114 cls : 'has-feedback',
8123 if (this.before || this.after) {
8126 cls : 'input-group',
8130 inputblock.cn.push({
8132 cls : 'input-group-addon',
8137 inputblock.cn.push(input);
8139 if(this.hasFeedback && !this.allowBlank){
8140 inputblock.cls += ' has-feedback';
8141 inputblock.cn.push(feedback);
8145 inputblock.cn.push({
8147 cls : 'input-group-addon',
8154 if (align ==='left' && this.fieldLabel.length) {
8155 Roo.log("left and has label");
8161 cls : 'control-label col-sm-' + this.labelWidth,
8162 html : this.fieldLabel
8166 cls : "col-sm-" + (12 - this.labelWidth),
8173 } else if ( this.fieldLabel.length) {
8179 //cls : 'input-group-addon',
8180 html : this.fieldLabel
8190 Roo.log(" no label && no align");
8200 if (this.disabled) {
8201 input.disabled=true;
8208 * return the real textarea element.
8210 inputEl: function ()
8212 return this.el.select('textarea.form-control',true).first();
8220 * trigger field - base class for combo..
8225 * @class Roo.bootstrap.TriggerField
8226 * @extends Roo.bootstrap.Input
8227 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8228 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8229 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8230 * for which you can provide a custom implementation. For example:
8232 var trigger = new Roo.bootstrap.TriggerField();
8233 trigger.onTriggerClick = myTriggerFn;
8234 trigger.applyTo('my-field');
8237 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8238 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8239 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8240 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8241 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8244 * Create a new TriggerField.
8245 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8246 * to the base TextField)
8248 Roo.bootstrap.TriggerField = function(config){
8249 this.mimicing = false;
8250 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8253 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8255 * @cfg {String} triggerClass A CSS class to apply to the trigger
8258 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8262 /** @cfg {Boolean} grow @hide */
8263 /** @cfg {Number} growMin @hide */
8264 /** @cfg {Number} growMax @hide */
8270 autoSize: Roo.emptyFn,
8277 actionMode : 'wrap',
8282 getAutoCreate : function(){
8284 var align = this.labelAlign || this.parentLabelAlign();
8289 cls: 'form-group' //input-group
8296 type : this.inputType,
8297 cls : 'form-control',
8298 autocomplete: 'new-password',
8299 placeholder : this.placeholder || ''
8303 input.name = this.name;
8306 input.cls += ' input-' + this.size;
8309 if (this.disabled) {
8310 input.disabled=true;
8313 var inputblock = input;
8315 if(this.hasFeedback && !this.allowBlank){
8319 cls: 'glyphicon form-control-feedback'
8323 cls : 'has-feedback',
8331 if (this.before || this.after) {
8334 cls : 'input-group',
8338 inputblock.cn.push({
8340 cls : 'input-group-addon',
8345 inputblock.cn.push(input);
8347 if(this.hasFeedback && !this.allowBlank){
8348 inputblock.cls += ' has-feedback';
8349 inputblock.cn.push(feedback);
8353 inputblock.cn.push({
8355 cls : 'input-group-addon',
8368 cls: 'form-hidden-field'
8376 Roo.log('multiple');
8384 cls: 'form-hidden-field'
8388 cls: 'select2-choices',
8392 cls: 'select2-search-field',
8405 cls: 'select2-container input-group',
8410 // cls: 'typeahead typeahead-long dropdown-menu',
8411 // style: 'display:none'
8416 if(!this.multiple && this.showToggleBtn){
8422 if (this.caret != false) {
8425 cls: 'fa fa-' + this.caret
8432 cls : 'input-group-addon btn dropdown-toggle',
8437 cls: 'combobox-clear',
8451 combobox.cls += ' select2-container-multi';
8454 if (align ==='left' && this.fieldLabel.length) {
8456 Roo.log("left and has label");
8462 cls : 'control-label col-sm-' + this.labelWidth,
8463 html : this.fieldLabel
8467 cls : "col-sm-" + (12 - this.labelWidth),
8474 } else if ( this.fieldLabel.length) {
8480 //cls : 'input-group-addon',
8481 html : this.fieldLabel
8491 Roo.log(" no label && no align");
8498 ['xs','sm','md','lg'].map(function(size){
8499 if (settings[size]) {
8500 cfg.cls += ' col-' + size + '-' + settings[size];
8511 onResize : function(w, h){
8512 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8513 // if(typeof w == 'number'){
8514 // var x = w - this.trigger.getWidth();
8515 // this.inputEl().setWidth(this.adjustWidth('input', x));
8516 // this.trigger.setStyle('left', x+'px');
8521 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8524 getResizeEl : function(){
8525 return this.inputEl();
8529 getPositionEl : function(){
8530 return this.inputEl();
8534 alignErrorIcon : function(){
8535 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8539 initEvents : function(){
8543 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8544 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8545 if(!this.multiple && this.showToggleBtn){
8546 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8547 if(this.hideTrigger){
8548 this.trigger.setDisplayed(false);
8550 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8554 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8557 //this.trigger.addClassOnOver('x-form-trigger-over');
8558 //this.trigger.addClassOnClick('x-form-trigger-click');
8561 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8565 createList : function()
8567 this.list = Roo.get(document.body).createChild({
8569 cls: 'typeahead typeahead-long dropdown-menu',
8570 style: 'display:none'
8573 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8578 initTrigger : function(){
8583 onDestroy : function(){
8585 this.trigger.removeAllListeners();
8586 // this.trigger.remove();
8589 // this.wrap.remove();
8591 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8595 onFocus : function(){
8596 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8599 this.wrap.addClass('x-trigger-wrap-focus');
8600 this.mimicing = true;
8601 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8602 if(this.monitorTab){
8603 this.el.on("keydown", this.checkTab, this);
8610 checkTab : function(e){
8611 if(e.getKey() == e.TAB){
8617 onBlur : function(){
8622 mimicBlur : function(e, t){
8624 if(!this.wrap.contains(t) && this.validateBlur()){
8631 triggerBlur : function(){
8632 this.mimicing = false;
8633 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8634 if(this.monitorTab){
8635 this.el.un("keydown", this.checkTab, this);
8637 //this.wrap.removeClass('x-trigger-wrap-focus');
8638 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8642 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8643 validateBlur : function(e, t){
8648 onDisable : function(){
8649 this.inputEl().dom.disabled = true;
8650 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8652 // this.wrap.addClass('x-item-disabled');
8657 onEnable : function(){
8658 this.inputEl().dom.disabled = false;
8659 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8661 // this.el.removeClass('x-item-disabled');
8666 onShow : function(){
8667 var ae = this.getActionEl();
8670 ae.dom.style.display = '';
8671 ae.dom.style.visibility = 'visible';
8677 onHide : function(){
8678 var ae = this.getActionEl();
8679 ae.dom.style.display = 'none';
8683 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8684 * by an implementing function.
8686 * @param {EventObject} e
8688 onTriggerClick : Roo.emptyFn
8692 * Ext JS Library 1.1.1
8693 * Copyright(c) 2006-2007, Ext JS, LLC.
8695 * Originally Released Under LGPL - original licence link has changed is not relivant.
8698 * <script type="text/javascript">
8703 * @class Roo.data.SortTypes
8705 * Defines the default sorting (casting?) comparison functions used when sorting data.
8707 Roo.data.SortTypes = {
8709 * Default sort that does nothing
8710 * @param {Mixed} s The value being converted
8711 * @return {Mixed} The comparison value
8718 * The regular expression used to strip tags
8722 stripTagsRE : /<\/?[^>]+>/gi,
8725 * Strips all HTML tags to sort on text only
8726 * @param {Mixed} s The value being converted
8727 * @return {String} The comparison value
8729 asText : function(s){
8730 return String(s).replace(this.stripTagsRE, "");
8734 * Strips all HTML tags to sort on text only - Case insensitive
8735 * @param {Mixed} s The value being converted
8736 * @return {String} The comparison value
8738 asUCText : function(s){
8739 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8743 * Case insensitive string
8744 * @param {Mixed} s The value being converted
8745 * @return {String} The comparison value
8747 asUCString : function(s) {
8748 return String(s).toUpperCase();
8753 * @param {Mixed} s The value being converted
8754 * @return {Number} The comparison value
8756 asDate : function(s) {
8760 if(s instanceof Date){
8763 return Date.parse(String(s));
8768 * @param {Mixed} s The value being converted
8769 * @return {Float} The comparison value
8771 asFloat : function(s) {
8772 var val = parseFloat(String(s).replace(/,/g, ""));
8773 if(isNaN(val)) val = 0;
8779 * @param {Mixed} s The value being converted
8780 * @return {Number} The comparison value
8782 asInt : function(s) {
8783 var val = parseInt(String(s).replace(/,/g, ""));
8784 if(isNaN(val)) val = 0;
8789 * Ext JS Library 1.1.1
8790 * Copyright(c) 2006-2007, Ext JS, LLC.
8792 * Originally Released Under LGPL - original licence link has changed is not relivant.
8795 * <script type="text/javascript">
8799 * @class Roo.data.Record
8800 * Instances of this class encapsulate both record <em>definition</em> information, and record
8801 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8802 * to access Records cached in an {@link Roo.data.Store} object.<br>
8804 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8805 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8808 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8810 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8811 * {@link #create}. The parameters are the same.
8812 * @param {Array} data An associative Array of data values keyed by the field name.
8813 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8814 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8815 * not specified an integer id is generated.
8817 Roo.data.Record = function(data, id){
8818 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8823 * Generate a constructor for a specific record layout.
8824 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8825 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8826 * Each field definition object may contain the following properties: <ul>
8827 * <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,
8828 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8829 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8830 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8831 * is being used, then this is a string containing the javascript expression to reference the data relative to
8832 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8833 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8834 * this may be omitted.</p></li>
8835 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8836 * <ul><li>auto (Default, implies no conversion)</li>
8841 * <li>date</li></ul></p></li>
8842 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8843 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8844 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8845 * by the Reader into an object that will be stored in the Record. It is passed the
8846 * following parameters:<ul>
8847 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8849 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8851 * <br>usage:<br><pre><code>
8852 var TopicRecord = Roo.data.Record.create(
8853 {name: 'title', mapping: 'topic_title'},
8854 {name: 'author', mapping: 'username'},
8855 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8856 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8857 {name: 'lastPoster', mapping: 'user2'},
8858 {name: 'excerpt', mapping: 'post_text'}
8861 var myNewRecord = new TopicRecord({
8862 title: 'Do my job please',
8865 lastPost: new Date(),
8866 lastPoster: 'Animal',
8867 excerpt: 'No way dude!'
8869 myStore.add(myNewRecord);
8874 Roo.data.Record.create = function(o){
8876 f.superclass.constructor.apply(this, arguments);
8878 Roo.extend(f, Roo.data.Record);
8879 var p = f.prototype;
8880 p.fields = new Roo.util.MixedCollection(false, function(field){
8883 for(var i = 0, len = o.length; i < len; i++){
8884 p.fields.add(new Roo.data.Field(o[i]));
8886 f.getField = function(name){
8887 return p.fields.get(name);
8892 Roo.data.Record.AUTO_ID = 1000;
8893 Roo.data.Record.EDIT = 'edit';
8894 Roo.data.Record.REJECT = 'reject';
8895 Roo.data.Record.COMMIT = 'commit';
8897 Roo.data.Record.prototype = {
8899 * Readonly flag - true if this record has been modified.
8908 join : function(store){
8913 * Set the named field to the specified value.
8914 * @param {String} name The name of the field to set.
8915 * @param {Object} value The value to set the field to.
8917 set : function(name, value){
8918 if(this.data[name] == value){
8925 if(typeof this.modified[name] == 'undefined'){
8926 this.modified[name] = this.data[name];
8928 this.data[name] = value;
8929 if(!this.editing && this.store){
8930 this.store.afterEdit(this);
8935 * Get the value of the named field.
8936 * @param {String} name The name of the field to get the value of.
8937 * @return {Object} The value of the field.
8939 get : function(name){
8940 return this.data[name];
8944 beginEdit : function(){
8945 this.editing = true;
8950 cancelEdit : function(){
8951 this.editing = false;
8952 delete this.modified;
8956 endEdit : function(){
8957 this.editing = false;
8958 if(this.dirty && this.store){
8959 this.store.afterEdit(this);
8964 * Usually called by the {@link Roo.data.Store} which owns the Record.
8965 * Rejects all changes made to the Record since either creation, or the last commit operation.
8966 * Modified fields are reverted to their original values.
8968 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8969 * of reject operations.
8971 reject : function(){
8972 var m = this.modified;
8974 if(typeof m[n] != "function"){
8975 this.data[n] = m[n];
8979 delete this.modified;
8980 this.editing = false;
8982 this.store.afterReject(this);
8987 * Usually called by the {@link Roo.data.Store} which owns the Record.
8988 * Commits all changes made to the Record since either creation, or the last commit operation.
8990 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8991 * of commit operations.
8993 commit : function(){
8995 delete this.modified;
8996 this.editing = false;
8998 this.store.afterCommit(this);
9003 hasError : function(){
9004 return this.error != null;
9008 clearError : function(){
9013 * Creates a copy of this record.
9014 * @param {String} id (optional) A new record id if you don't want to use this record's id
9017 copy : function(newId) {
9018 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9022 * Ext JS Library 1.1.1
9023 * Copyright(c) 2006-2007, Ext JS, LLC.
9025 * Originally Released Under LGPL - original licence link has changed is not relivant.
9028 * <script type="text/javascript">
9034 * @class Roo.data.Store
9035 * @extends Roo.util.Observable
9036 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9037 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9039 * 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
9040 * has no knowledge of the format of the data returned by the Proxy.<br>
9042 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9043 * instances from the data object. These records are cached and made available through accessor functions.
9045 * Creates a new Store.
9046 * @param {Object} config A config object containing the objects needed for the Store to access data,
9047 * and read the data into Records.
9049 Roo.data.Store = function(config){
9050 this.data = new Roo.util.MixedCollection(false);
9051 this.data.getKey = function(o){
9054 this.baseParams = {};
9061 "multisort" : "_multisort"
9064 if(config && config.data){
9065 this.inlineData = config.data;
9069 Roo.apply(this, config);
9071 if(this.reader){ // reader passed
9072 this.reader = Roo.factory(this.reader, Roo.data);
9073 this.reader.xmodule = this.xmodule || false;
9074 if(!this.recordType){
9075 this.recordType = this.reader.recordType;
9077 if(this.reader.onMetaChange){
9078 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9082 if(this.recordType){
9083 this.fields = this.recordType.prototype.fields;
9089 * @event datachanged
9090 * Fires when the data cache has changed, and a widget which is using this Store
9091 * as a Record cache should refresh its view.
9092 * @param {Store} this
9097 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9098 * @param {Store} this
9099 * @param {Object} meta The JSON metadata
9104 * Fires when Records have been added to the Store
9105 * @param {Store} this
9106 * @param {Roo.data.Record[]} records The array of Records added
9107 * @param {Number} index The index at which the record(s) were added
9112 * Fires when a Record has been removed from the Store
9113 * @param {Store} this
9114 * @param {Roo.data.Record} record The Record that was removed
9115 * @param {Number} index The index at which the record was removed
9120 * Fires when a Record has been updated
9121 * @param {Store} this
9122 * @param {Roo.data.Record} record The Record that was updated
9123 * @param {String} operation The update operation being performed. Value may be one of:
9125 Roo.data.Record.EDIT
9126 Roo.data.Record.REJECT
9127 Roo.data.Record.COMMIT
9133 * Fires when the data cache has been cleared.
9134 * @param {Store} this
9139 * Fires before a request is made for a new data object. If the beforeload handler returns false
9140 * the load action will be canceled.
9141 * @param {Store} this
9142 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9146 * @event beforeloadadd
9147 * Fires after a new set of Records has been loaded.
9148 * @param {Store} this
9149 * @param {Roo.data.Record[]} records The Records that were loaded
9150 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9152 beforeloadadd : true,
9155 * Fires after a new set of Records has been loaded, before they are added to the store.
9156 * @param {Store} this
9157 * @param {Roo.data.Record[]} records The Records that were loaded
9158 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9159 * @params {Object} return from reader
9163 * @event loadexception
9164 * Fires if an exception occurs in the Proxy during loading.
9165 * Called with the signature of the Proxy's "loadexception" event.
9166 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9169 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9170 * @param {Object} load options
9171 * @param {Object} jsonData from your request (normally this contains the Exception)
9173 loadexception : true
9177 this.proxy = Roo.factory(this.proxy, Roo.data);
9178 this.proxy.xmodule = this.xmodule || false;
9179 this.relayEvents(this.proxy, ["loadexception"]);
9181 this.sortToggle = {};
9182 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9184 Roo.data.Store.superclass.constructor.call(this);
9186 if(this.inlineData){
9187 this.loadData(this.inlineData);
9188 delete this.inlineData;
9192 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9194 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9195 * without a remote query - used by combo/forms at present.
9199 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9202 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9205 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9206 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9209 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9210 * on any HTTP request
9213 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9216 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9220 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9221 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9226 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9227 * loaded or when a record is removed. (defaults to false).
9229 pruneModifiedRecords : false,
9235 * Add Records to the Store and fires the add event.
9236 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9238 add : function(records){
9239 records = [].concat(records);
9240 for(var i = 0, len = records.length; i < len; i++){
9241 records[i].join(this);
9243 var index = this.data.length;
9244 this.data.addAll(records);
9245 this.fireEvent("add", this, records, index);
9249 * Remove a Record from the Store and fires the remove event.
9250 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9252 remove : function(record){
9253 var index = this.data.indexOf(record);
9254 this.data.removeAt(index);
9255 if(this.pruneModifiedRecords){
9256 this.modified.remove(record);
9258 this.fireEvent("remove", this, record, index);
9262 * Remove all Records from the Store and fires the clear event.
9264 removeAll : function(){
9266 if(this.pruneModifiedRecords){
9269 this.fireEvent("clear", this);
9273 * Inserts Records to the Store at the given index and fires the add event.
9274 * @param {Number} index The start index at which to insert the passed Records.
9275 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9277 insert : function(index, records){
9278 records = [].concat(records);
9279 for(var i = 0, len = records.length; i < len; i++){
9280 this.data.insert(index, records[i]);
9281 records[i].join(this);
9283 this.fireEvent("add", this, records, index);
9287 * Get the index within the cache of the passed Record.
9288 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9289 * @return {Number} The index of the passed Record. Returns -1 if not found.
9291 indexOf : function(record){
9292 return this.data.indexOf(record);
9296 * Get the index within the cache of the Record with the passed id.
9297 * @param {String} id The id of the Record to find.
9298 * @return {Number} The index of the Record. Returns -1 if not found.
9300 indexOfId : function(id){
9301 return this.data.indexOfKey(id);
9305 * Get the Record with the specified id.
9306 * @param {String} id The id of the Record to find.
9307 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9309 getById : function(id){
9310 return this.data.key(id);
9314 * Get the Record at the specified index.
9315 * @param {Number} index The index of the Record to find.
9316 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9318 getAt : function(index){
9319 return this.data.itemAt(index);
9323 * Returns a range of Records between specified indices.
9324 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9325 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9326 * @return {Roo.data.Record[]} An array of Records
9328 getRange : function(start, end){
9329 return this.data.getRange(start, end);
9333 storeOptions : function(o){
9334 o = Roo.apply({}, o);
9337 this.lastOptions = o;
9341 * Loads the Record cache from the configured Proxy using the configured Reader.
9343 * If using remote paging, then the first load call must specify the <em>start</em>
9344 * and <em>limit</em> properties in the options.params property to establish the initial
9345 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9347 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9348 * and this call will return before the new data has been loaded. Perform any post-processing
9349 * in a callback function, or in a "load" event handler.</strong>
9351 * @param {Object} options An object containing properties which control loading options:<ul>
9352 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9353 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9354 * passed the following arguments:<ul>
9355 * <li>r : Roo.data.Record[]</li>
9356 * <li>options: Options object from the load call</li>
9357 * <li>success: Boolean success indicator</li></ul></li>
9358 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9359 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9362 load : function(options){
9363 options = options || {};
9364 if(this.fireEvent("beforeload", this, options) !== false){
9365 this.storeOptions(options);
9366 var p = Roo.apply(options.params || {}, this.baseParams);
9367 // if meta was not loaded from remote source.. try requesting it.
9368 if (!this.reader.metaFromRemote) {
9371 if(this.sortInfo && this.remoteSort){
9372 var pn = this.paramNames;
9373 p[pn["sort"]] = this.sortInfo.field;
9374 p[pn["dir"]] = this.sortInfo.direction;
9376 if (this.multiSort) {
9377 var pn = this.paramNames;
9378 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9381 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9386 * Reloads the Record cache from the configured Proxy using the configured Reader and
9387 * the options from the last load operation performed.
9388 * @param {Object} options (optional) An object containing properties which may override the options
9389 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9390 * the most recently used options are reused).
9392 reload : function(options){
9393 this.load(Roo.applyIf(options||{}, this.lastOptions));
9397 // Called as a callback by the Reader during a load operation.
9398 loadRecords : function(o, options, success){
9399 if(!o || success === false){
9400 if(success !== false){
9401 this.fireEvent("load", this, [], options, o);
9403 if(options.callback){
9404 options.callback.call(options.scope || this, [], options, false);
9408 // if data returned failure - throw an exception.
9409 if (o.success === false) {
9410 // show a message if no listener is registered.
9411 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9412 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9414 // loadmask wil be hooked into this..
9415 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9418 var r = o.records, t = o.totalRecords || r.length;
9420 this.fireEvent("beforeloadadd", this, r, options, o);
9422 if(!options || options.add !== true){
9423 if(this.pruneModifiedRecords){
9426 for(var i = 0, len = r.length; i < len; i++){
9430 this.data = this.snapshot;
9431 delete this.snapshot;
9434 this.data.addAll(r);
9435 this.totalLength = t;
9437 this.fireEvent("datachanged", this);
9439 this.totalLength = Math.max(t, this.data.length+r.length);
9442 this.fireEvent("load", this, r, options, o);
9443 if(options.callback){
9444 options.callback.call(options.scope || this, r, options, true);
9450 * Loads data from a passed data block. A Reader which understands the format of the data
9451 * must have been configured in the constructor.
9452 * @param {Object} data The data block from which to read the Records. The format of the data expected
9453 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9454 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9456 loadData : function(o, append){
9457 var r = this.reader.readRecords(o);
9458 this.loadRecords(r, {add: append}, true);
9462 * Gets the number of cached records.
9464 * <em>If using paging, this may not be the total size of the dataset. If the data object
9465 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9466 * the data set size</em>
9468 getCount : function(){
9469 return this.data.length || 0;
9473 * Gets the total number of records in the dataset as returned by the server.
9475 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9476 * the dataset size</em>
9478 getTotalCount : function(){
9479 return this.totalLength || 0;
9483 * Returns the sort state of the Store as an object with two properties:
9485 field {String} The name of the field by which the Records are sorted
9486 direction {String} The sort order, "ASC" or "DESC"
9489 getSortState : function(){
9490 return this.sortInfo;
9494 applySort : function(){
9495 if(this.sortInfo && !this.remoteSort){
9496 var s = this.sortInfo, f = s.field;
9497 var st = this.fields.get(f).sortType;
9498 var fn = function(r1, r2){
9499 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9500 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9502 this.data.sort(s.direction, fn);
9503 if(this.snapshot && this.snapshot != this.data){
9504 this.snapshot.sort(s.direction, fn);
9510 * Sets the default sort column and order to be used by the next load operation.
9511 * @param {String} fieldName The name of the field to sort by.
9512 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9514 setDefaultSort : function(field, dir){
9515 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9520 * If remote sorting is used, the sort is performed on the server, and the cache is
9521 * reloaded. If local sorting is used, the cache is sorted internally.
9522 * @param {String} fieldName The name of the field to sort by.
9523 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9525 sort : function(fieldName, dir){
9526 var f = this.fields.get(fieldName);
9528 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9530 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9531 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9536 this.sortToggle[f.name] = dir;
9537 this.sortInfo = {field: f.name, direction: dir};
9538 if(!this.remoteSort){
9540 this.fireEvent("datachanged", this);
9542 this.load(this.lastOptions);
9547 * Calls the specified function for each of the Records in the cache.
9548 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9549 * Returning <em>false</em> aborts and exits the iteration.
9550 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9552 each : function(fn, scope){
9553 this.data.each(fn, scope);
9557 * Gets all records modified since the last commit. Modified records are persisted across load operations
9558 * (e.g., during paging).
9559 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9561 getModifiedRecords : function(){
9562 return this.modified;
9566 createFilterFn : function(property, value, anyMatch){
9567 if(!value.exec){ // not a regex
9568 value = String(value);
9569 if(value.length == 0){
9572 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9575 return value.test(r.data[property]);
9580 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9581 * @param {String} property A field on your records
9582 * @param {Number} start The record index to start at (defaults to 0)
9583 * @param {Number} end The last record index to include (defaults to length - 1)
9584 * @return {Number} The sum
9586 sum : function(property, start, end){
9587 var rs = this.data.items, v = 0;
9589 end = (end || end === 0) ? end : rs.length-1;
9591 for(var i = start; i <= end; i++){
9592 v += (rs[i].data[property] || 0);
9598 * Filter the records by a specified property.
9599 * @param {String} field A field on your records
9600 * @param {String/RegExp} value Either a string that the field
9601 * should start with or a RegExp to test against the field
9602 * @param {Boolean} anyMatch True to match any part not just the beginning
9604 filter : function(property, value, anyMatch){
9605 var fn = this.createFilterFn(property, value, anyMatch);
9606 return fn ? this.filterBy(fn) : this.clearFilter();
9610 * Filter by a function. The specified function will be called with each
9611 * record in this data source. If the function returns true the record is included,
9612 * otherwise it is filtered.
9613 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9614 * @param {Object} scope (optional) The scope of the function (defaults to this)
9616 filterBy : function(fn, scope){
9617 this.snapshot = this.snapshot || this.data;
9618 this.data = this.queryBy(fn, scope||this);
9619 this.fireEvent("datachanged", this);
9623 * Query the records by a specified property.
9624 * @param {String} field A field on your records
9625 * @param {String/RegExp} value Either a string that the field
9626 * should start with or a RegExp to test against the field
9627 * @param {Boolean} anyMatch True to match any part not just the beginning
9628 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9630 query : function(property, value, anyMatch){
9631 var fn = this.createFilterFn(property, value, anyMatch);
9632 return fn ? this.queryBy(fn) : this.data.clone();
9636 * Query by a function. The specified function will be called with each
9637 * record in this data source. If the function returns true the record is included
9639 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9640 * @param {Object} scope (optional) The scope of the function (defaults to this)
9641 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9643 queryBy : function(fn, scope){
9644 var data = this.snapshot || this.data;
9645 return data.filterBy(fn, scope||this);
9649 * Collects unique values for a particular dataIndex from this store.
9650 * @param {String} dataIndex The property to collect
9651 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9652 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9653 * @return {Array} An array of the unique values
9655 collect : function(dataIndex, allowNull, bypassFilter){
9656 var d = (bypassFilter === true && this.snapshot) ?
9657 this.snapshot.items : this.data.items;
9658 var v, sv, r = [], l = {};
9659 for(var i = 0, len = d.length; i < len; i++){
9660 v = d[i].data[dataIndex];
9662 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9671 * Revert to a view of the Record cache with no filtering applied.
9672 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9674 clearFilter : function(suppressEvent){
9675 if(this.snapshot && this.snapshot != this.data){
9676 this.data = this.snapshot;
9677 delete this.snapshot;
9678 if(suppressEvent !== true){
9679 this.fireEvent("datachanged", this);
9685 afterEdit : function(record){
9686 if(this.modified.indexOf(record) == -1){
9687 this.modified.push(record);
9689 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9693 afterReject : function(record){
9694 this.modified.remove(record);
9695 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9699 afterCommit : function(record){
9700 this.modified.remove(record);
9701 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9705 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9706 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9708 commitChanges : function(){
9709 var m = this.modified.slice(0);
9711 for(var i = 0, len = m.length; i < len; i++){
9717 * Cancel outstanding changes on all changed records.
9719 rejectChanges : function(){
9720 var m = this.modified.slice(0);
9722 for(var i = 0, len = m.length; i < len; i++){
9727 onMetaChange : function(meta, rtype, o){
9728 this.recordType = rtype;
9729 this.fields = rtype.prototype.fields;
9730 delete this.snapshot;
9731 this.sortInfo = meta.sortInfo || this.sortInfo;
9733 this.fireEvent('metachange', this, this.reader.meta);
9736 moveIndex : function(data, type)
9738 var index = this.indexOf(data);
9740 var newIndex = index + type;
9744 this.insert(newIndex, data);
9749 * Ext JS Library 1.1.1
9750 * Copyright(c) 2006-2007, Ext JS, LLC.
9752 * Originally Released Under LGPL - original licence link has changed is not relivant.
9755 * <script type="text/javascript">
9759 * @class Roo.data.SimpleStore
9760 * @extends Roo.data.Store
9761 * Small helper class to make creating Stores from Array data easier.
9762 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9763 * @cfg {Array} fields An array of field definition objects, or field name strings.
9764 * @cfg {Array} data The multi-dimensional array of data
9766 * @param {Object} config
9768 Roo.data.SimpleStore = function(config){
9769 Roo.data.SimpleStore.superclass.constructor.call(this, {
9771 reader: new Roo.data.ArrayReader({
9774 Roo.data.Record.create(config.fields)
9776 proxy : new Roo.data.MemoryProxy(config.data)
9780 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9782 * Ext JS Library 1.1.1
9783 * Copyright(c) 2006-2007, Ext JS, LLC.
9785 * Originally Released Under LGPL - original licence link has changed is not relivant.
9788 * <script type="text/javascript">
9793 * @extends Roo.data.Store
9794 * @class Roo.data.JsonStore
9795 * Small helper class to make creating Stores for JSON data easier. <br/>
9797 var store = new Roo.data.JsonStore({
9798 url: 'get-images.php',
9800 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9803 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9804 * JsonReader and HttpProxy (unless inline data is provided).</b>
9805 * @cfg {Array} fields An array of field definition objects, or field name strings.
9807 * @param {Object} config
9809 Roo.data.JsonStore = function(c){
9810 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9811 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9812 reader: new Roo.data.JsonReader(c, c.fields)
9815 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9817 * Ext JS Library 1.1.1
9818 * Copyright(c) 2006-2007, Ext JS, LLC.
9820 * Originally Released Under LGPL - original licence link has changed is not relivant.
9823 * <script type="text/javascript">
9827 Roo.data.Field = function(config){
9828 if(typeof config == "string"){
9829 config = {name: config};
9831 Roo.apply(this, config);
9837 var st = Roo.data.SortTypes;
9838 // named sortTypes are supported, here we look them up
9839 if(typeof this.sortType == "string"){
9840 this.sortType = st[this.sortType];
9843 // set default sortType for strings and dates
9847 this.sortType = st.asUCString;
9850 this.sortType = st.asDate;
9853 this.sortType = st.none;
9858 var stripRe = /[\$,%]/g;
9860 // prebuilt conversion function for this field, instead of
9861 // switching every time we're reading a value
9863 var cv, dateFormat = this.dateFormat;
9868 cv = function(v){ return v; };
9871 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9875 return v !== undefined && v !== null && v !== '' ?
9876 parseInt(String(v).replace(stripRe, ""), 10) : '';
9881 return v !== undefined && v !== null && v !== '' ?
9882 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9887 cv = function(v){ return v === true || v === "true" || v == 1; };
9894 if(v instanceof Date){
9898 if(dateFormat == "timestamp"){
9899 return new Date(v*1000);
9901 return Date.parseDate(v, dateFormat);
9903 var parsed = Date.parse(v);
9904 return parsed ? new Date(parsed) : null;
9913 Roo.data.Field.prototype = {
9921 * Ext JS Library 1.1.1
9922 * Copyright(c) 2006-2007, Ext JS, LLC.
9924 * Originally Released Under LGPL - original licence link has changed is not relivant.
9927 * <script type="text/javascript">
9930 // Base class for reading structured data from a data source. This class is intended to be
9931 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9934 * @class Roo.data.DataReader
9935 * Base class for reading structured data from a data source. This class is intended to be
9936 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9939 Roo.data.DataReader = function(meta, recordType){
9943 this.recordType = recordType instanceof Array ?
9944 Roo.data.Record.create(recordType) : recordType;
9947 Roo.data.DataReader.prototype = {
9949 * Create an empty record
9950 * @param {Object} data (optional) - overlay some values
9951 * @return {Roo.data.Record} record created.
9953 newRow : function(d) {
9955 this.recordType.prototype.fields.each(function(c) {
9957 case 'int' : da[c.name] = 0; break;
9958 case 'date' : da[c.name] = new Date(); break;
9959 case 'float' : da[c.name] = 0.0; break;
9960 case 'boolean' : da[c.name] = false; break;
9961 default : da[c.name] = ""; break;
9965 return new this.recordType(Roo.apply(da, d));
9970 * Ext JS Library 1.1.1
9971 * Copyright(c) 2006-2007, Ext JS, LLC.
9973 * Originally Released Under LGPL - original licence link has changed is not relivant.
9976 * <script type="text/javascript">
9980 * @class Roo.data.DataProxy
9981 * @extends Roo.data.Observable
9982 * This class is an abstract base class for implementations which provide retrieval of
9983 * unformatted data objects.<br>
9985 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9986 * (of the appropriate type which knows how to parse the data object) to provide a block of
9987 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9989 * Custom implementations must implement the load method as described in
9990 * {@link Roo.data.HttpProxy#load}.
9992 Roo.data.DataProxy = function(){
9996 * Fires before a network request is made to retrieve a data object.
9997 * @param {Object} This DataProxy object.
9998 * @param {Object} params The params parameter to the load function.
10003 * Fires before the load method's callback is called.
10004 * @param {Object} This DataProxy object.
10005 * @param {Object} o The data object.
10006 * @param {Object} arg The callback argument object passed to the load function.
10010 * @event loadexception
10011 * Fires if an Exception occurs during data retrieval.
10012 * @param {Object} This DataProxy object.
10013 * @param {Object} o The data object.
10014 * @param {Object} arg The callback argument object passed to the load function.
10015 * @param {Object} e The Exception.
10017 loadexception : true
10019 Roo.data.DataProxy.superclass.constructor.call(this);
10022 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10025 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10029 * Ext JS Library 1.1.1
10030 * Copyright(c) 2006-2007, Ext JS, LLC.
10032 * Originally Released Under LGPL - original licence link has changed is not relivant.
10035 * <script type="text/javascript">
10038 * @class Roo.data.MemoryProxy
10039 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10040 * to the Reader when its load method is called.
10042 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10044 Roo.data.MemoryProxy = function(data){
10048 Roo.data.MemoryProxy.superclass.constructor.call(this);
10052 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10054 * Load data from the requested source (in this case an in-memory
10055 * data object passed to the constructor), read the data object into
10056 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10057 * process that block using the passed callback.
10058 * @param {Object} params This parameter is not used by the MemoryProxy class.
10059 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10060 * object into a block of Roo.data.Records.
10061 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10062 * The function must be passed <ul>
10063 * <li>The Record block object</li>
10064 * <li>The "arg" argument from the load function</li>
10065 * <li>A boolean success indicator</li>
10067 * @param {Object} scope The scope in which to call the callback
10068 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10070 load : function(params, reader, callback, scope, arg){
10071 params = params || {};
10074 result = reader.readRecords(this.data);
10076 this.fireEvent("loadexception", this, arg, null, e);
10077 callback.call(scope, null, arg, false);
10080 callback.call(scope, result, arg, true);
10084 update : function(params, records){
10089 * Ext JS Library 1.1.1
10090 * Copyright(c) 2006-2007, Ext JS, LLC.
10092 * Originally Released Under LGPL - original licence link has changed is not relivant.
10095 * <script type="text/javascript">
10098 * @class Roo.data.HttpProxy
10099 * @extends Roo.data.DataProxy
10100 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10101 * configured to reference a certain URL.<br><br>
10103 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10104 * from which the running page was served.<br><br>
10106 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10108 * Be aware that to enable the browser to parse an XML document, the server must set
10109 * the Content-Type header in the HTTP response to "text/xml".
10111 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10112 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10113 * will be used to make the request.
10115 Roo.data.HttpProxy = function(conn){
10116 Roo.data.HttpProxy.superclass.constructor.call(this);
10117 // is conn a conn config or a real conn?
10119 this.useAjax = !conn || !conn.events;
10123 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10124 // thse are take from connection...
10127 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10130 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10131 * extra parameters to each request made by this object. (defaults to undefined)
10134 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10135 * to each request made by this object. (defaults to undefined)
10138 * @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)
10141 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10144 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10150 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10154 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10155 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10156 * a finer-grained basis than the DataProxy events.
10158 getConnection : function(){
10159 return this.useAjax ? Roo.Ajax : this.conn;
10163 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10164 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10165 * process that block using the passed callback.
10166 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10167 * for the request to the remote server.
10168 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10169 * object into a block of Roo.data.Records.
10170 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10171 * The function must be passed <ul>
10172 * <li>The Record block object</li>
10173 * <li>The "arg" argument from the load function</li>
10174 * <li>A boolean success indicator</li>
10176 * @param {Object} scope The scope in which to call the callback
10177 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10179 load : function(params, reader, callback, scope, arg){
10180 if(this.fireEvent("beforeload", this, params) !== false){
10182 params : params || {},
10184 callback : callback,
10189 callback : this.loadResponse,
10193 Roo.applyIf(o, this.conn);
10194 if(this.activeRequest){
10195 Roo.Ajax.abort(this.activeRequest);
10197 this.activeRequest = Roo.Ajax.request(o);
10199 this.conn.request(o);
10202 callback.call(scope||this, null, arg, false);
10207 loadResponse : function(o, success, response){
10208 delete this.activeRequest;
10210 this.fireEvent("loadexception", this, o, response);
10211 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10216 result = o.reader.read(response);
10218 this.fireEvent("loadexception", this, o, response, e);
10219 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10223 this.fireEvent("load", this, o, o.request.arg);
10224 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10228 update : function(dataSet){
10233 updateResponse : function(dataSet){
10238 * Ext JS Library 1.1.1
10239 * Copyright(c) 2006-2007, Ext JS, LLC.
10241 * Originally Released Under LGPL - original licence link has changed is not relivant.
10244 * <script type="text/javascript">
10248 * @class Roo.data.ScriptTagProxy
10249 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10250 * other than the originating domain of the running page.<br><br>
10252 * <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
10253 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10255 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10256 * source code that is used as the source inside a <script> tag.<br><br>
10258 * In order for the browser to process the returned data, the server must wrap the data object
10259 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10260 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10261 * depending on whether the callback name was passed:
10264 boolean scriptTag = false;
10265 String cb = request.getParameter("callback");
10268 response.setContentType("text/javascript");
10270 response.setContentType("application/x-json");
10272 Writer out = response.getWriter();
10274 out.write(cb + "(");
10276 out.print(dataBlock.toJsonString());
10283 * @param {Object} config A configuration object.
10285 Roo.data.ScriptTagProxy = function(config){
10286 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10287 Roo.apply(this, config);
10288 this.head = document.getElementsByTagName("head")[0];
10291 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10293 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10295 * @cfg {String} url The URL from which to request the data object.
10298 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10302 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10303 * the server the name of the callback function set up by the load call to process the returned data object.
10304 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10305 * javascript output which calls this named function passing the data object as its only parameter.
10307 callbackParam : "callback",
10309 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10310 * name to the request.
10315 * Load data from the configured URL, read the data object into
10316 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10317 * process that block using the passed callback.
10318 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10319 * for the request to the remote server.
10320 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10321 * object into a block of Roo.data.Records.
10322 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10323 * The function must be passed <ul>
10324 * <li>The Record block object</li>
10325 * <li>The "arg" argument from the load function</li>
10326 * <li>A boolean success indicator</li>
10328 * @param {Object} scope The scope in which to call the callback
10329 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10331 load : function(params, reader, callback, scope, arg){
10332 if(this.fireEvent("beforeload", this, params) !== false){
10334 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10336 var url = this.url;
10337 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10339 url += "&_dc=" + (new Date().getTime());
10341 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10344 cb : "stcCallback"+transId,
10345 scriptId : "stcScript"+transId,
10349 callback : callback,
10355 window[trans.cb] = function(o){
10356 conn.handleResponse(o, trans);
10359 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10361 if(this.autoAbort !== false){
10365 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10367 var script = document.createElement("script");
10368 script.setAttribute("src", url);
10369 script.setAttribute("type", "text/javascript");
10370 script.setAttribute("id", trans.scriptId);
10371 this.head.appendChild(script);
10373 this.trans = trans;
10375 callback.call(scope||this, null, arg, false);
10380 isLoading : function(){
10381 return this.trans ? true : false;
10385 * Abort the current server request.
10387 abort : function(){
10388 if(this.isLoading()){
10389 this.destroyTrans(this.trans);
10394 destroyTrans : function(trans, isLoaded){
10395 this.head.removeChild(document.getElementById(trans.scriptId));
10396 clearTimeout(trans.timeoutId);
10398 window[trans.cb] = undefined;
10400 delete window[trans.cb];
10403 // if hasn't been loaded, wait for load to remove it to prevent script error
10404 window[trans.cb] = function(){
10405 window[trans.cb] = undefined;
10407 delete window[trans.cb];
10414 handleResponse : function(o, trans){
10415 this.trans = false;
10416 this.destroyTrans(trans, true);
10419 result = trans.reader.readRecords(o);
10421 this.fireEvent("loadexception", this, o, trans.arg, e);
10422 trans.callback.call(trans.scope||window, null, trans.arg, false);
10425 this.fireEvent("load", this, o, trans.arg);
10426 trans.callback.call(trans.scope||window, result, trans.arg, true);
10430 handleFailure : function(trans){
10431 this.trans = false;
10432 this.destroyTrans(trans, false);
10433 this.fireEvent("loadexception", this, null, trans.arg);
10434 trans.callback.call(trans.scope||window, null, trans.arg, false);
10438 * Ext JS Library 1.1.1
10439 * Copyright(c) 2006-2007, Ext JS, LLC.
10441 * Originally Released Under LGPL - original licence link has changed is not relivant.
10444 * <script type="text/javascript">
10448 * @class Roo.data.JsonReader
10449 * @extends Roo.data.DataReader
10450 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10451 * based on mappings in a provided Roo.data.Record constructor.
10453 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10454 * in the reply previously.
10459 var RecordDef = Roo.data.Record.create([
10460 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10461 {name: 'occupation'} // This field will use "occupation" as the mapping.
10463 var myReader = new Roo.data.JsonReader({
10464 totalProperty: "results", // The property which contains the total dataset size (optional)
10465 root: "rows", // The property which contains an Array of row objects
10466 id: "id" // The property within each row object that provides an ID for the record (optional)
10470 * This would consume a JSON file like this:
10472 { 'results': 2, 'rows': [
10473 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10474 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10477 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10478 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10479 * paged from the remote server.
10480 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10481 * @cfg {String} root name of the property which contains the Array of row objects.
10482 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10484 * Create a new JsonReader
10485 * @param {Object} meta Metadata configuration options
10486 * @param {Object} recordType Either an Array of field definition objects,
10487 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10489 Roo.data.JsonReader = function(meta, recordType){
10492 // set some defaults:
10493 Roo.applyIf(meta, {
10494 totalProperty: 'total',
10495 successProperty : 'success',
10500 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10502 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10505 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10506 * Used by Store query builder to append _requestMeta to params.
10509 metaFromRemote : false,
10511 * This method is only used by a DataProxy which has retrieved data from a remote server.
10512 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10513 * @return {Object} data A data block which is used by an Roo.data.Store object as
10514 * a cache of Roo.data.Records.
10516 read : function(response){
10517 var json = response.responseText;
10519 var o = /* eval:var:o */ eval("("+json+")");
10521 throw {message: "JsonReader.read: Json object not found"};
10527 this.metaFromRemote = true;
10528 this.meta = o.metaData;
10529 this.recordType = Roo.data.Record.create(o.metaData.fields);
10530 this.onMetaChange(this.meta, this.recordType, o);
10532 return this.readRecords(o);
10535 // private function a store will implement
10536 onMetaChange : function(meta, recordType, o){
10543 simpleAccess: function(obj, subsc) {
10550 getJsonAccessor: function(){
10552 return function(expr) {
10554 return(re.test(expr))
10555 ? new Function("obj", "return obj." + expr)
10560 return Roo.emptyFn;
10565 * Create a data block containing Roo.data.Records from an XML document.
10566 * @param {Object} o An object which contains an Array of row objects in the property specified
10567 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10568 * which contains the total size of the dataset.
10569 * @return {Object} data A data block which is used by an Roo.data.Store object as
10570 * a cache of Roo.data.Records.
10572 readRecords : function(o){
10574 * After any data loads, the raw JSON data is available for further custom processing.
10578 var s = this.meta, Record = this.recordType,
10579 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10581 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10583 if(s.totalProperty) {
10584 this.getTotal = this.getJsonAccessor(s.totalProperty);
10586 if(s.successProperty) {
10587 this.getSuccess = this.getJsonAccessor(s.successProperty);
10589 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10591 var g = this.getJsonAccessor(s.id);
10592 this.getId = function(rec) {
10594 return (r === undefined || r === "") ? null : r;
10597 this.getId = function(){return null;};
10600 for(var jj = 0; jj < fl; jj++){
10602 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10603 this.ef[jj] = this.getJsonAccessor(map);
10607 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10608 if(s.totalProperty){
10609 var vt = parseInt(this.getTotal(o), 10);
10614 if(s.successProperty){
10615 var vs = this.getSuccess(o);
10616 if(vs === false || vs === 'false'){
10621 for(var i = 0; i < c; i++){
10624 var id = this.getId(n);
10625 for(var j = 0; j < fl; j++){
10627 var v = this.ef[j](n);
10629 Roo.log('missing convert for ' + f.name);
10633 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10635 var record = new Record(values, id);
10637 records[i] = record;
10643 totalRecords : totalRecords
10648 * Ext JS Library 1.1.1
10649 * Copyright(c) 2006-2007, Ext JS, LLC.
10651 * Originally Released Under LGPL - original licence link has changed is not relivant.
10654 * <script type="text/javascript">
10658 * @class Roo.data.ArrayReader
10659 * @extends Roo.data.DataReader
10660 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10661 * Each element of that Array represents a row of data fields. The
10662 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10663 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10667 var RecordDef = Roo.data.Record.create([
10668 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10669 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10671 var myReader = new Roo.data.ArrayReader({
10672 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10676 * This would consume an Array like this:
10678 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10680 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10682 * Create a new JsonReader
10683 * @param {Object} meta Metadata configuration options.
10684 * @param {Object} recordType Either an Array of field definition objects
10685 * as specified to {@link Roo.data.Record#create},
10686 * or an {@link Roo.data.Record} object
10687 * created using {@link Roo.data.Record#create}.
10689 Roo.data.ArrayReader = function(meta, recordType){
10690 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10693 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10695 * Create a data block containing Roo.data.Records from an XML document.
10696 * @param {Object} o An Array of row objects which represents the dataset.
10697 * @return {Object} data A data block which is used by an Roo.data.Store object as
10698 * a cache of Roo.data.Records.
10700 readRecords : function(o){
10701 var sid = this.meta ? this.meta.id : null;
10702 var recordType = this.recordType, fields = recordType.prototype.fields;
10705 for(var i = 0; i < root.length; i++){
10708 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10709 for(var j = 0, jlen = fields.length; j < jlen; j++){
10710 var f = fields.items[j];
10711 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10712 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10714 values[f.name] = v;
10716 var record = new recordType(values, id);
10718 records[records.length] = record;
10722 totalRecords : records.length
10731 * @class Roo.bootstrap.ComboBox
10732 * @extends Roo.bootstrap.TriggerField
10733 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10734 * @cfg {Boolean} append (true|false) default false
10735 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10736 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10737 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10738 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10739 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10741 * Create a new ComboBox.
10742 * @param {Object} config Configuration options
10744 Roo.bootstrap.ComboBox = function(config){
10745 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10749 * Fires when the dropdown list is expanded
10750 * @param {Roo.bootstrap.ComboBox} combo This combo box
10755 * Fires when the dropdown list is collapsed
10756 * @param {Roo.bootstrap.ComboBox} combo This combo box
10760 * @event beforeselect
10761 * Fires before a list item is selected. Return false to cancel the selection.
10762 * @param {Roo.bootstrap.ComboBox} combo This combo box
10763 * @param {Roo.data.Record} record The data record returned from the underlying store
10764 * @param {Number} index The index of the selected item in the dropdown list
10766 'beforeselect' : true,
10769 * Fires when a list item is selected
10770 * @param {Roo.bootstrap.ComboBox} combo This combo box
10771 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10772 * @param {Number} index The index of the selected item in the dropdown list
10776 * @event beforequery
10777 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10778 * The event object passed has these properties:
10779 * @param {Roo.bootstrap.ComboBox} combo This combo box
10780 * @param {String} query The query
10781 * @param {Boolean} forceAll true to force "all" query
10782 * @param {Boolean} cancel true to cancel the query
10783 * @param {Object} e The query event object
10785 'beforequery': true,
10788 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10789 * @param {Roo.bootstrap.ComboBox} combo This combo box
10794 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10795 * @param {Roo.bootstrap.ComboBox} combo This combo box
10796 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10801 * Fires when the remove value from the combobox array
10802 * @param {Roo.bootstrap.ComboBox} combo This combo box
10806 * @event specialfilter
10807 * Fires when specialfilter
10808 * @param {Roo.bootstrap.ComboBox} combo This combo box
10810 'specialfilter' : true
10815 this.tickItems = [];
10817 this.selectedIndex = -1;
10818 if(this.mode == 'local'){
10819 if(config.queryDelay === undefined){
10820 this.queryDelay = 10;
10822 if(config.minChars === undefined){
10828 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10831 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10832 * rendering into an Roo.Editor, defaults to false)
10835 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10836 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10839 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10842 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10843 * the dropdown list (defaults to undefined, with no header element)
10847 * @cfg {String/Roo.Template} tpl The template to use to render the output
10851 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10853 listWidth: undefined,
10855 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10856 * mode = 'remote' or 'text' if mode = 'local')
10858 displayField: undefined,
10861 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10862 * mode = 'remote' or 'value' if mode = 'local').
10863 * Note: use of a valueField requires the user make a selection
10864 * in order for a value to be mapped.
10866 valueField: undefined,
10870 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10871 * field's data value (defaults to the underlying DOM element's name)
10873 hiddenName: undefined,
10875 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10879 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10881 selectedClass: 'active',
10884 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10888 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10889 * anchor positions (defaults to 'tl-bl')
10891 listAlign: 'tl-bl?',
10893 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10897 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10898 * query specified by the allQuery config option (defaults to 'query')
10900 triggerAction: 'query',
10902 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10903 * (defaults to 4, does not apply if editable = false)
10907 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10908 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10912 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10913 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10917 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10918 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10922 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10923 * when editable = true (defaults to false)
10925 selectOnFocus:false,
10927 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10929 queryParam: 'query',
10931 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10932 * when mode = 'remote' (defaults to 'Loading...')
10934 loadingText: 'Loading...',
10936 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10940 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10944 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10945 * traditional select (defaults to true)
10949 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10953 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10957 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10958 * listWidth has a higher value)
10962 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10963 * allow the user to set arbitrary text into the field (defaults to false)
10965 forceSelection:false,
10967 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10968 * if typeAhead = true (defaults to 250)
10970 typeAheadDelay : 250,
10972 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10973 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10975 valueNotFoundText : undefined,
10977 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10979 blockFocus : false,
10982 * @cfg {Boolean} disableClear Disable showing of clear button.
10984 disableClear : false,
10986 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10988 alwaysQuery : false,
10991 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10996 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10998 invalidClass : "has-warning",
11001 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11003 validClass : "has-success",
11006 * @cfg {Boolean} specialFilter (true|false) special filter default false
11008 specialFilter : false,
11020 btnPosition : 'right',
11021 triggerList : true,
11022 showToggleBtn : true,
11023 // element that contains real text value.. (when hidden is used..)
11025 getAutoCreate : function()
11032 if(!this.tickable){
11033 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11038 * ComboBox with tickable selections
11041 var align = this.labelAlign || this.parentLabelAlign();
11044 cls : 'form-group roo-combobox-tickable' //input-group
11049 cls : 'tickable-buttons',
11054 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11061 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11068 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11075 buttons.cn.unshift({
11077 cls: 'select2-search-field-input'
11083 Roo.each(buttons.cn, function(c){
11085 c.cls += ' btn-' + _this.size;
11088 if (_this.disabled) {
11099 cls: 'form-hidden-field'
11103 cls: 'select2-choices',
11107 cls: 'select2-search-field',
11119 cls: 'select2-container input-group select2-container-multi',
11124 // cls: 'typeahead typeahead-long dropdown-menu',
11125 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11130 if(this.hasFeedback && !this.allowBlank){
11134 cls: 'glyphicon form-control-feedback'
11137 combobox.cn.push(feedback);
11140 if (align ==='left' && this.fieldLabel.length) {
11142 Roo.log("left and has label");
11148 cls : 'control-label col-sm-' + this.labelWidth,
11149 html : this.fieldLabel
11153 cls : "col-sm-" + (12 - this.labelWidth),
11160 } else if ( this.fieldLabel.length) {
11166 //cls : 'input-group-addon',
11167 html : this.fieldLabel
11177 Roo.log(" no label && no align");
11184 ['xs','sm','md','lg'].map(function(size){
11185 if (settings[size]) {
11186 cfg.cls += ' col-' + size + '-' + settings[size];
11195 initEvents: function()
11199 throw "can not find store for combo";
11201 this.store = Roo.factory(this.store, Roo.data);
11204 this.initTickableEvents();
11208 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11210 if(this.hiddenName){
11212 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11214 this.hiddenField.dom.value =
11215 this.hiddenValue !== undefined ? this.hiddenValue :
11216 this.value !== undefined ? this.value : '';
11218 // prevent input submission
11219 this.el.dom.removeAttribute('name');
11220 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11225 // this.el.dom.setAttribute('autocomplete', 'off');
11228 var cls = 'x-combo-list';
11230 //this.list = new Roo.Layer({
11231 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11237 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11238 _this.list.setWidth(lw);
11241 this.list.on('mouseover', this.onViewOver, this);
11242 this.list.on('mousemove', this.onViewMove, this);
11244 this.list.on('scroll', this.onViewScroll, this);
11247 this.list.swallowEvent('mousewheel');
11248 this.assetHeight = 0;
11251 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11252 this.assetHeight += this.header.getHeight();
11255 this.innerList = this.list.createChild({cls:cls+'-inner'});
11256 this.innerList.on('mouseover', this.onViewOver, this);
11257 this.innerList.on('mousemove', this.onViewMove, this);
11258 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11260 if(this.allowBlank && !this.pageSize && !this.disableClear){
11261 this.footer = this.list.createChild({cls:cls+'-ft'});
11262 this.pageTb = new Roo.Toolbar(this.footer);
11266 this.footer = this.list.createChild({cls:cls+'-ft'});
11267 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11268 {pageSize: this.pageSize});
11272 if (this.pageTb && this.allowBlank && !this.disableClear) {
11274 this.pageTb.add(new Roo.Toolbar.Fill(), {
11275 cls: 'x-btn-icon x-btn-clear',
11277 handler: function()
11280 _this.clearValue();
11281 _this.onSelect(false, -1);
11286 this.assetHeight += this.footer.getHeight();
11291 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11294 this.view = new Roo.View(this.list, this.tpl, {
11295 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11297 //this.view.wrapEl.setDisplayed(false);
11298 this.view.on('click', this.onViewClick, this);
11302 this.store.on('beforeload', this.onBeforeLoad, this);
11303 this.store.on('load', this.onLoad, this);
11304 this.store.on('loadexception', this.onLoadException, this);
11306 if(this.resizable){
11307 this.resizer = new Roo.Resizable(this.list, {
11308 pinned:true, handles:'se'
11310 this.resizer.on('resize', function(r, w, h){
11311 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11312 this.listWidth = w;
11313 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11314 this.restrictHeight();
11316 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11319 if(!this.editable){
11320 this.editable = true;
11321 this.setEditable(false);
11326 if (typeof(this.events.add.listeners) != 'undefined') {
11328 this.addicon = this.wrap.createChild(
11329 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11331 this.addicon.on('click', function(e) {
11332 this.fireEvent('add', this);
11335 if (typeof(this.events.edit.listeners) != 'undefined') {
11337 this.editicon = this.wrap.createChild(
11338 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11339 if (this.addicon) {
11340 this.editicon.setStyle('margin-left', '40px');
11342 this.editicon.on('click', function(e) {
11344 // we fire even if inothing is selected..
11345 this.fireEvent('edit', this, this.lastData );
11351 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11352 "up" : function(e){
11353 this.inKeyMode = true;
11357 "down" : function(e){
11358 if(!this.isExpanded()){
11359 this.onTriggerClick();
11361 this.inKeyMode = true;
11366 "enter" : function(e){
11367 // this.onViewClick();
11371 if(this.fireEvent("specialkey", this, e)){
11372 this.onViewClick(false);
11378 "esc" : function(e){
11382 "tab" : function(e){
11385 if(this.fireEvent("specialkey", this, e)){
11386 this.onViewClick(false);
11394 doRelay : function(foo, bar, hname){
11395 if(hname == 'down' || this.scope.isExpanded()){
11396 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11405 this.queryDelay = Math.max(this.queryDelay || 10,
11406 this.mode == 'local' ? 10 : 250);
11409 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11411 if(this.typeAhead){
11412 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11414 if(this.editable !== false){
11415 this.inputEl().on("keyup", this.onKeyUp, this);
11417 if(this.forceSelection){
11418 this.inputEl().on('blur', this.doForce, this);
11422 this.choices = this.el.select('ul.select2-choices', true).first();
11423 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11427 initTickableEvents: function()
11431 if(this.hiddenName){
11433 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11435 this.hiddenField.dom.value =
11436 this.hiddenValue !== undefined ? this.hiddenValue :
11437 this.value !== undefined ? this.value : '';
11439 // prevent input submission
11440 this.el.dom.removeAttribute('name');
11441 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11446 // this.list = this.el.select('ul.dropdown-menu',true).first();
11448 this.choices = this.el.select('ul.select2-choices', true).first();
11449 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11450 if(this.triggerList){
11451 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11454 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11455 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11457 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11458 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11460 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11461 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11463 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11464 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11465 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11468 this.cancelBtn.hide();
11473 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11474 _this.list.setWidth(lw);
11477 this.list.on('mouseover', this.onViewOver, this);
11478 this.list.on('mousemove', this.onViewMove, this);
11480 this.list.on('scroll', this.onViewScroll, this);
11483 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>';
11486 this.view = new Roo.View(this.list, this.tpl, {
11487 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11490 //this.view.wrapEl.setDisplayed(false);
11491 this.view.on('click', this.onViewClick, this);
11495 this.store.on('beforeload', this.onBeforeLoad, this);
11496 this.store.on('load', this.onLoad, this);
11497 this.store.on('loadexception', this.onLoadException, this);
11500 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11501 "up" : function(e){
11502 this.inKeyMode = true;
11506 "down" : function(e){
11507 this.inKeyMode = true;
11511 "enter" : function(e){
11512 if(this.fireEvent("specialkey", this, e)){
11513 this.onViewClick(false);
11519 "esc" : function(e){
11520 this.onTickableFooterButtonClick(e, false, false);
11523 "tab" : function(e){
11524 this.fireEvent("specialkey", this, e);
11526 this.onTickableFooterButtonClick(e, false, false);
11533 doRelay : function(e, fn, key){
11534 if(this.scope.isExpanded()){
11535 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11544 this.queryDelay = Math.max(this.queryDelay || 10,
11545 this.mode == 'local' ? 10 : 250);
11548 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11550 if(this.typeAhead){
11551 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11554 if(this.editable !== false){
11555 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11560 onDestroy : function(){
11562 this.view.setStore(null);
11563 this.view.el.removeAllListeners();
11564 this.view.el.remove();
11565 this.view.purgeListeners();
11568 this.list.dom.innerHTML = '';
11572 this.store.un('beforeload', this.onBeforeLoad, this);
11573 this.store.un('load', this.onLoad, this);
11574 this.store.un('loadexception', this.onLoadException, this);
11576 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11580 fireKey : function(e){
11581 if(e.isNavKeyPress() && !this.list.isVisible()){
11582 this.fireEvent("specialkey", this, e);
11587 onResize: function(w, h){
11588 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11590 // if(typeof w != 'number'){
11591 // // we do not handle it!?!?
11594 // var tw = this.trigger.getWidth();
11595 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11596 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11598 // this.inputEl().setWidth( this.adjustWidth('input', x));
11600 // //this.trigger.setStyle('left', x+'px');
11602 // if(this.list && this.listWidth === undefined){
11603 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11604 // this.list.setWidth(lw);
11605 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11613 * Allow or prevent the user from directly editing the field text. If false is passed,
11614 * the user will only be able to select from the items defined in the dropdown list. This method
11615 * is the runtime equivalent of setting the 'editable' config option at config time.
11616 * @param {Boolean} value True to allow the user to directly edit the field text
11618 setEditable : function(value){
11619 if(value == this.editable){
11622 this.editable = value;
11624 this.inputEl().dom.setAttribute('readOnly', true);
11625 this.inputEl().on('mousedown', this.onTriggerClick, this);
11626 this.inputEl().addClass('x-combo-noedit');
11628 this.inputEl().dom.setAttribute('readOnly', false);
11629 this.inputEl().un('mousedown', this.onTriggerClick, this);
11630 this.inputEl().removeClass('x-combo-noedit');
11636 onBeforeLoad : function(combo,opts){
11637 if(!this.hasFocus){
11641 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11643 this.restrictHeight();
11644 this.selectedIndex = -1;
11648 onLoad : function(){
11650 this.hasQuery = false;
11652 if(!this.hasFocus){
11656 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11657 this.loading.hide();
11660 if(this.store.getCount() > 0){
11662 this.restrictHeight();
11663 if(this.lastQuery == this.allQuery){
11664 if(this.editable && !this.tickable){
11665 this.inputEl().dom.select();
11669 !this.selectByValue(this.value, true) &&
11672 !this.store.lastOptions ||
11673 typeof(this.store.lastOptions.add) == 'undefined' ||
11674 this.store.lastOptions.add != true
11677 this.select(0, true);
11680 if(this.autoFocus){
11683 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11684 this.taTask.delay(this.typeAheadDelay);
11688 this.onEmptyResults();
11694 onLoadException : function()
11696 this.hasQuery = false;
11698 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11699 this.loading.hide();
11702 if(this.tickable && this.editable){
11708 Roo.log(this.store.reader.jsonData);
11709 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11711 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11717 onTypeAhead : function(){
11718 if(this.store.getCount() > 0){
11719 var r = this.store.getAt(0);
11720 var newValue = r.data[this.displayField];
11721 var len = newValue.length;
11722 var selStart = this.getRawValue().length;
11724 if(selStart != len){
11725 this.setRawValue(newValue);
11726 this.selectText(selStart, newValue.length);
11732 onSelect : function(record, index){
11734 if(this.fireEvent('beforeselect', this, record, index) !== false){
11736 this.setFromData(index > -1 ? record.data : false);
11739 this.fireEvent('select', this, record, index);
11744 * Returns the currently selected field value or empty string if no value is set.
11745 * @return {String} value The selected value
11747 getValue : function(){
11750 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11753 if(this.valueField){
11754 return typeof this.value != 'undefined' ? this.value : '';
11756 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11761 * Clears any text/value currently set in the field
11763 clearValue : function(){
11764 if(this.hiddenField){
11765 this.hiddenField.dom.value = '';
11768 this.setRawValue('');
11769 this.lastSelectionText = '';
11770 this.lastData = false;
11775 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11776 * will be displayed in the field. If the value does not match the data value of an existing item,
11777 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11778 * Otherwise the field will be blank (although the value will still be set).
11779 * @param {String} value The value to match
11781 setValue : function(v){
11788 if(this.valueField){
11789 var r = this.findRecord(this.valueField, v);
11791 text = r.data[this.displayField];
11792 }else if(this.valueNotFoundText !== undefined){
11793 text = this.valueNotFoundText;
11796 this.lastSelectionText = text;
11797 if(this.hiddenField){
11798 this.hiddenField.dom.value = v;
11800 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11804 * @property {Object} the last set data for the element
11809 * Sets the value of the field based on a object which is related to the record format for the store.
11810 * @param {Object} value the value to set as. or false on reset?
11812 setFromData : function(o){
11819 var dv = ''; // display value
11820 var vv = ''; // value value..
11822 if (this.displayField) {
11823 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11825 // this is an error condition!!!
11826 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11829 if(this.valueField){
11830 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11833 if(this.hiddenField){
11834 this.hiddenField.dom.value = vv;
11836 this.lastSelectionText = dv;
11837 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11841 // no hidden field.. - we store the value in 'value', but still display
11842 // display field!!!!
11843 this.lastSelectionText = dv;
11844 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11850 reset : function(){
11851 // overridden so that last data is reset..
11858 this.setValue(this.originalValue);
11859 this.clearInvalid();
11860 this.lastData = false;
11862 this.view.clearSelections();
11866 findRecord : function(prop, value){
11868 if(this.store.getCount() > 0){
11869 this.store.each(function(r){
11870 if(r.data[prop] == value){
11880 getName: function()
11882 // returns hidden if it's set..
11883 if (!this.rendered) {return ''};
11884 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11888 onViewMove : function(e, t){
11889 this.inKeyMode = false;
11893 onViewOver : function(e, t){
11894 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11897 var item = this.view.findItemFromChild(t);
11900 var index = this.view.indexOf(item);
11901 this.select(index, false);
11906 onViewClick : function(view, doFocus, el, e)
11908 var index = this.view.getSelectedIndexes()[0];
11910 var r = this.store.getAt(index);
11914 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11921 Roo.each(this.tickItems, function(v,k){
11923 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11924 _this.tickItems.splice(k, 1);
11926 if(typeof(e) == 'undefined' && view == false){
11927 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11939 this.tickItems.push(r.data);
11941 if(typeof(e) == 'undefined' && view == false){
11942 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11949 this.onSelect(r, index);
11951 if(doFocus !== false && !this.blockFocus){
11952 this.inputEl().focus();
11957 restrictHeight : function(){
11958 //this.innerList.dom.style.height = '';
11959 //var inner = this.innerList.dom;
11960 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11961 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11962 //this.list.beginUpdate();
11963 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11964 this.list.alignTo(this.inputEl(), this.listAlign);
11965 this.list.alignTo(this.inputEl(), this.listAlign);
11966 //this.list.endUpdate();
11970 onEmptyResults : function(){
11972 if(this.tickable && this.editable){
11973 this.restrictHeight();
11981 * Returns true if the dropdown list is expanded, else false.
11983 isExpanded : function(){
11984 return this.list.isVisible();
11988 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11989 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11990 * @param {String} value The data value of the item to select
11991 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11992 * selected item if it is not currently in view (defaults to true)
11993 * @return {Boolean} True if the value matched an item in the list, else false
11995 selectByValue : function(v, scrollIntoView){
11996 if(v !== undefined && v !== null){
11997 var r = this.findRecord(this.valueField || this.displayField, v);
11999 this.select(this.store.indexOf(r), scrollIntoView);
12007 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12008 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12009 * @param {Number} index The zero-based index of the list item to select
12010 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12011 * selected item if it is not currently in view (defaults to true)
12013 select : function(index, scrollIntoView){
12014 this.selectedIndex = index;
12015 this.view.select(index);
12016 if(scrollIntoView !== false){
12017 var el = this.view.getNode(index);
12019 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12022 this.list.scrollChildIntoView(el, false);
12028 selectNext : function(){
12029 var ct = this.store.getCount();
12031 if(this.selectedIndex == -1){
12033 }else if(this.selectedIndex < ct-1){
12034 this.select(this.selectedIndex+1);
12040 selectPrev : function(){
12041 var ct = this.store.getCount();
12043 if(this.selectedIndex == -1){
12045 }else if(this.selectedIndex != 0){
12046 this.select(this.selectedIndex-1);
12052 onKeyUp : function(e){
12053 if(this.editable !== false && !e.isSpecialKey()){
12054 this.lastKey = e.getKey();
12055 this.dqTask.delay(this.queryDelay);
12060 validateBlur : function(){
12061 return !this.list || !this.list.isVisible();
12065 initQuery : function(){
12067 var v = this.getRawValue();
12069 if(this.tickable && this.editable){
12070 v = this.tickableInputEl().getValue();
12077 doForce : function(){
12078 if(this.inputEl().dom.value.length > 0){
12079 this.inputEl().dom.value =
12080 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12086 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12087 * query allowing the query action to be canceled if needed.
12088 * @param {String} query The SQL query to execute
12089 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12090 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12091 * saved in the current store (defaults to false)
12093 doQuery : function(q, forceAll){
12095 if(q === undefined || q === null){
12100 forceAll: forceAll,
12104 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12109 forceAll = qe.forceAll;
12110 if(forceAll === true || (q.length >= this.minChars)){
12112 this.hasQuery = true;
12114 if(this.lastQuery != q || this.alwaysQuery){
12115 this.lastQuery = q;
12116 if(this.mode == 'local'){
12117 this.selectedIndex = -1;
12119 this.store.clearFilter();
12122 if(this.specialFilter){
12123 this.fireEvent('specialfilter', this);
12128 this.store.filter(this.displayField, q);
12131 this.store.fireEvent("datachanged", this.store);
12138 this.store.baseParams[this.queryParam] = q;
12140 var options = {params : this.getParams(q)};
12143 options.add = true;
12144 options.params.start = this.page * this.pageSize;
12147 this.store.load(options);
12150 * this code will make the page width larger, at the beginning, the list not align correctly,
12151 * we should expand the list on onLoad
12152 * so command out it
12157 this.selectedIndex = -1;
12162 this.loadNext = false;
12166 getParams : function(q){
12168 //p[this.queryParam] = q;
12172 p.limit = this.pageSize;
12178 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12180 collapse : function(){
12181 if(!this.isExpanded()){
12188 this.hasFocus = false;
12190 this.cancelBtn.hide();
12191 this.trigger.show();
12194 this.tickableInputEl().dom.value = '';
12195 this.tickableInputEl().blur();
12200 Roo.get(document).un('mousedown', this.collapseIf, this);
12201 Roo.get(document).un('mousewheel', this.collapseIf, this);
12202 if (!this.editable) {
12203 Roo.get(document).un('keydown', this.listKeyPress, this);
12205 this.fireEvent('collapse', this);
12209 collapseIf : function(e){
12210 var in_combo = e.within(this.el);
12211 var in_list = e.within(this.list);
12212 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12214 if (in_combo || in_list || is_list) {
12215 //e.stopPropagation();
12220 this.onTickableFooterButtonClick(e, false, false);
12228 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12230 expand : function(){
12232 if(this.isExpanded() || !this.hasFocus){
12236 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12237 this.list.setWidth(lw);
12244 this.restrictHeight();
12248 this.tickItems = Roo.apply([], this.item);
12251 this.cancelBtn.show();
12252 this.trigger.hide();
12255 this.tickableInputEl().focus();
12260 Roo.get(document).on('mousedown', this.collapseIf, this);
12261 Roo.get(document).on('mousewheel', this.collapseIf, this);
12262 if (!this.editable) {
12263 Roo.get(document).on('keydown', this.listKeyPress, this);
12266 this.fireEvent('expand', this);
12270 // Implements the default empty TriggerField.onTriggerClick function
12271 onTriggerClick : function(e)
12273 Roo.log('trigger click');
12275 if(this.disabled || !this.triggerList){
12280 this.loadNext = false;
12282 if(this.isExpanded()){
12284 if (!this.blockFocus) {
12285 this.inputEl().focus();
12289 this.hasFocus = true;
12290 if(this.triggerAction == 'all') {
12291 this.doQuery(this.allQuery, true);
12293 this.doQuery(this.getRawValue());
12295 if (!this.blockFocus) {
12296 this.inputEl().focus();
12301 onTickableTriggerClick : function(e)
12308 this.loadNext = false;
12309 this.hasFocus = true;
12311 if(this.triggerAction == 'all') {
12312 this.doQuery(this.allQuery, true);
12314 this.doQuery(this.getRawValue());
12318 onSearchFieldClick : function(e)
12320 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12321 this.onTickableFooterButtonClick(e, false, false);
12325 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12330 this.loadNext = false;
12331 this.hasFocus = true;
12333 if(this.triggerAction == 'all') {
12334 this.doQuery(this.allQuery, true);
12336 this.doQuery(this.getRawValue());
12340 listKeyPress : function(e)
12342 //Roo.log('listkeypress');
12343 // scroll to first matching element based on key pres..
12344 if (e.isSpecialKey()) {
12347 var k = String.fromCharCode(e.getKey()).toUpperCase();
12350 var csel = this.view.getSelectedNodes();
12351 var cselitem = false;
12353 var ix = this.view.indexOf(csel[0]);
12354 cselitem = this.store.getAt(ix);
12355 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12361 this.store.each(function(v) {
12363 // start at existing selection.
12364 if (cselitem.id == v.id) {
12370 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12371 match = this.store.indexOf(v);
12377 if (match === false) {
12378 return true; // no more action?
12381 this.view.select(match);
12382 var sn = Roo.get(this.view.getSelectedNodes()[0])
12383 sn.scrollIntoView(sn.dom.parentNode, false);
12386 onViewScroll : function(e, t){
12388 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){
12392 this.hasQuery = true;
12394 this.loading = this.list.select('.loading', true).first();
12396 if(this.loading === null){
12397 this.list.createChild({
12399 cls: 'loading select2-more-results select2-active',
12400 html: 'Loading more results...'
12403 this.loading = this.list.select('.loading', true).first();
12405 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12407 this.loading.hide();
12410 this.loading.show();
12415 this.loadNext = true;
12417 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12422 addItem : function(o)
12424 var dv = ''; // display value
12426 if (this.displayField) {
12427 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12429 // this is an error condition!!!
12430 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12437 var choice = this.choices.createChild({
12439 cls: 'select2-search-choice',
12448 cls: 'select2-search-choice-close',
12453 }, this.searchField);
12455 var close = choice.select('a.select2-search-choice-close', true).first()
12457 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12465 this.inputEl().dom.value = '';
12470 onRemoveItem : function(e, _self, o)
12472 e.preventDefault();
12474 this.lastItem = Roo.apply([], this.item);
12476 var index = this.item.indexOf(o.data) * 1;
12479 Roo.log('not this item?!');
12483 this.item.splice(index, 1);
12488 this.fireEvent('remove', this, e);
12494 syncValue : function()
12496 if(!this.item.length){
12503 Roo.each(this.item, function(i){
12504 if(_this.valueField){
12505 value.push(i[_this.valueField]);
12512 this.value = value.join(',');
12514 if(this.hiddenField){
12515 this.hiddenField.dom.value = this.value;
12518 this.store.fireEvent("datachanged", this.store);
12521 clearItem : function()
12523 if(!this.multiple){
12529 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12538 inputEl: function ()
12541 return this.searchField;
12543 return this.el.select('input.form-control',true).first();
12547 onTickableFooterButtonClick : function(e, btn, el)
12549 e.preventDefault();
12551 this.lastItem = Roo.apply([], this.item);
12553 if(btn && btn.name == 'cancel'){
12554 this.tickItems = Roo.apply([], this.item);
12563 Roo.each(this.tickItems, function(o){
12571 validate : function()
12573 var v = this.getRawValue();
12576 v = this.getValue();
12579 if(this.disabled || this.allowBlank || v.length){
12584 this.markInvalid();
12588 tickableInputEl : function()
12590 if(!this.tickable || !this.editable){
12591 return this.inputEl();
12594 return this.inputEl().select('.select2-search-field-input', true).first();
12600 * @cfg {Boolean} grow
12604 * @cfg {Number} growMin
12608 * @cfg {Number} growMax
12618 * Ext JS Library 1.1.1
12619 * Copyright(c) 2006-2007, Ext JS, LLC.
12621 * Originally Released Under LGPL - original licence link has changed is not relivant.
12624 * <script type="text/javascript">
12629 * @extends Roo.util.Observable
12630 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12631 * This class also supports single and multi selection modes. <br>
12632 * Create a data model bound view:
12634 var store = new Roo.data.Store(...);
12636 var view = new Roo.View({
12638 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12640 singleSelect: true,
12641 selectedClass: "ydataview-selected",
12645 // listen for node click?
12646 view.on("click", function(vw, index, node, e){
12647 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12651 dataModel.load("foobar.xml");
12653 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12655 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12656 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12658 * Note: old style constructor is still suported (container, template, config)
12661 * Create a new View
12662 * @param {Object} config The config object
12665 Roo.View = function(config, depreciated_tpl, depreciated_config){
12667 this.parent = false;
12669 if (typeof(depreciated_tpl) == 'undefined') {
12670 // new way.. - universal constructor.
12671 Roo.apply(this, config);
12672 this.el = Roo.get(this.el);
12675 this.el = Roo.get(config);
12676 this.tpl = depreciated_tpl;
12677 Roo.apply(this, depreciated_config);
12679 this.wrapEl = this.el.wrap().wrap();
12680 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12683 if(typeof(this.tpl) == "string"){
12684 this.tpl = new Roo.Template(this.tpl);
12686 // support xtype ctors..
12687 this.tpl = new Roo.factory(this.tpl, Roo);
12691 this.tpl.compile();
12696 * @event beforeclick
12697 * Fires before a click is processed. Returns false to cancel the default action.
12698 * @param {Roo.View} this
12699 * @param {Number} index The index of the target node
12700 * @param {HTMLElement} node The target node
12701 * @param {Roo.EventObject} e The raw event object
12703 "beforeclick" : true,
12706 * Fires when a template node is clicked.
12707 * @param {Roo.View} this
12708 * @param {Number} index The index of the target node
12709 * @param {HTMLElement} node The target node
12710 * @param {Roo.EventObject} e The raw event object
12715 * Fires when a template node is double clicked.
12716 * @param {Roo.View} this
12717 * @param {Number} index The index of the target node
12718 * @param {HTMLElement} node The target node
12719 * @param {Roo.EventObject} e The raw event object
12723 * @event contextmenu
12724 * Fires when a template node is right clicked.
12725 * @param {Roo.View} this
12726 * @param {Number} index The index of the target node
12727 * @param {HTMLElement} node The target node
12728 * @param {Roo.EventObject} e The raw event object
12730 "contextmenu" : true,
12732 * @event selectionchange
12733 * Fires when the selected nodes change.
12734 * @param {Roo.View} this
12735 * @param {Array} selections Array of the selected nodes
12737 "selectionchange" : true,
12740 * @event beforeselect
12741 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12742 * @param {Roo.View} this
12743 * @param {HTMLElement} node The node to be selected
12744 * @param {Array} selections Array of currently selected nodes
12746 "beforeselect" : true,
12748 * @event preparedata
12749 * Fires on every row to render, to allow you to change the data.
12750 * @param {Roo.View} this
12751 * @param {Object} data to be rendered (change this)
12753 "preparedata" : true
12761 "click": this.onClick,
12762 "dblclick": this.onDblClick,
12763 "contextmenu": this.onContextMenu,
12767 this.selections = [];
12769 this.cmp = new Roo.CompositeElementLite([]);
12771 this.store = Roo.factory(this.store, Roo.data);
12772 this.setStore(this.store, true);
12775 if ( this.footer && this.footer.xtype) {
12777 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12779 this.footer.dataSource = this.store
12780 this.footer.container = fctr;
12781 this.footer = Roo.factory(this.footer, Roo);
12782 fctr.insertFirst(this.el);
12784 // this is a bit insane - as the paging toolbar seems to detach the el..
12785 // dom.parentNode.parentNode.parentNode
12786 // they get detached?
12790 Roo.View.superclass.constructor.call(this);
12795 Roo.extend(Roo.View, Roo.util.Observable, {
12798 * @cfg {Roo.data.Store} store Data store to load data from.
12803 * @cfg {String|Roo.Element} el The container element.
12808 * @cfg {String|Roo.Template} tpl The template used by this View
12812 * @cfg {String} dataName the named area of the template to use as the data area
12813 * Works with domtemplates roo-name="name"
12817 * @cfg {String} selectedClass The css class to add to selected nodes
12819 selectedClass : "x-view-selected",
12821 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12826 * @cfg {String} text to display on mask (default Loading)
12830 * @cfg {Boolean} multiSelect Allow multiple selection
12832 multiSelect : false,
12834 * @cfg {Boolean} singleSelect Allow single selection
12836 singleSelect: false,
12839 * @cfg {Boolean} toggleSelect - selecting
12841 toggleSelect : false,
12844 * @cfg {Boolean} tickable - selecting
12849 * Returns the element this view is bound to.
12850 * @return {Roo.Element}
12852 getEl : function(){
12853 return this.wrapEl;
12859 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12861 refresh : function(){
12862 //Roo.log('refresh');
12865 // if we are using something like 'domtemplate', then
12866 // the what gets used is:
12867 // t.applySubtemplate(NAME, data, wrapping data..)
12868 // the outer template then get' applied with
12869 // the store 'extra data'
12870 // and the body get's added to the
12871 // roo-name="data" node?
12872 // <span class='roo-tpl-{name}'></span> ?????
12876 this.clearSelections();
12877 this.el.update("");
12879 var records = this.store.getRange();
12880 if(records.length < 1) {
12882 // is this valid?? = should it render a template??
12884 this.el.update(this.emptyText);
12888 if (this.dataName) {
12889 this.el.update(t.apply(this.store.meta)); //????
12890 el = this.el.child('.roo-tpl-' + this.dataName);
12893 for(var i = 0, len = records.length; i < len; i++){
12894 var data = this.prepareData(records[i].data, i, records[i]);
12895 this.fireEvent("preparedata", this, data, i, records[i]);
12897 var d = Roo.apply({}, data);
12900 Roo.apply(d, {'roo-id' : Roo.id()});
12904 Roo.each(this.parent.item, function(item){
12905 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12908 Roo.apply(d, {'roo-data-checked' : 'checked'});
12912 html[html.length] = Roo.util.Format.trim(
12914 t.applySubtemplate(this.dataName, d, this.store.meta) :
12921 el.update(html.join(""));
12922 this.nodes = el.dom.childNodes;
12923 this.updateIndexes(0);
12928 * Function to override to reformat the data that is sent to
12929 * the template for each node.
12930 * DEPRICATED - use the preparedata event handler.
12931 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12932 * a JSON object for an UpdateManager bound view).
12934 prepareData : function(data, index, record)
12936 this.fireEvent("preparedata", this, data, index, record);
12940 onUpdate : function(ds, record){
12941 // Roo.log('on update');
12942 this.clearSelections();
12943 var index = this.store.indexOf(record);
12944 var n = this.nodes[index];
12945 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12946 n.parentNode.removeChild(n);
12947 this.updateIndexes(index, index);
12953 onAdd : function(ds, records, index)
12955 //Roo.log(['on Add', ds, records, index] );
12956 this.clearSelections();
12957 if(this.nodes.length == 0){
12961 var n = this.nodes[index];
12962 for(var i = 0, len = records.length; i < len; i++){
12963 var d = this.prepareData(records[i].data, i, records[i]);
12965 this.tpl.insertBefore(n, d);
12968 this.tpl.append(this.el, d);
12971 this.updateIndexes(index);
12974 onRemove : function(ds, record, index){
12975 // Roo.log('onRemove');
12976 this.clearSelections();
12977 var el = this.dataName ?
12978 this.el.child('.roo-tpl-' + this.dataName) :
12981 el.dom.removeChild(this.nodes[index]);
12982 this.updateIndexes(index);
12986 * Refresh an individual node.
12987 * @param {Number} index
12989 refreshNode : function(index){
12990 this.onUpdate(this.store, this.store.getAt(index));
12993 updateIndexes : function(startIndex, endIndex){
12994 var ns = this.nodes;
12995 startIndex = startIndex || 0;
12996 endIndex = endIndex || ns.length - 1;
12997 for(var i = startIndex; i <= endIndex; i++){
12998 ns[i].nodeIndex = i;
13003 * Changes the data store this view uses and refresh the view.
13004 * @param {Store} store
13006 setStore : function(store, initial){
13007 if(!initial && this.store){
13008 this.store.un("datachanged", this.refresh);
13009 this.store.un("add", this.onAdd);
13010 this.store.un("remove", this.onRemove);
13011 this.store.un("update", this.onUpdate);
13012 this.store.un("clear", this.refresh);
13013 this.store.un("beforeload", this.onBeforeLoad);
13014 this.store.un("load", this.onLoad);
13015 this.store.un("loadexception", this.onLoad);
13019 store.on("datachanged", this.refresh, this);
13020 store.on("add", this.onAdd, this);
13021 store.on("remove", this.onRemove, this);
13022 store.on("update", this.onUpdate, this);
13023 store.on("clear", this.refresh, this);
13024 store.on("beforeload", this.onBeforeLoad, this);
13025 store.on("load", this.onLoad, this);
13026 store.on("loadexception", this.onLoad, this);
13034 * onbeforeLoad - masks the loading area.
13037 onBeforeLoad : function(store,opts)
13039 //Roo.log('onBeforeLoad');
13041 this.el.update("");
13043 this.el.mask(this.mask ? this.mask : "Loading" );
13045 onLoad : function ()
13052 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13053 * @param {HTMLElement} node
13054 * @return {HTMLElement} The template node
13056 findItemFromChild : function(node){
13057 var el = this.dataName ?
13058 this.el.child('.roo-tpl-' + this.dataName,true) :
13061 if(!node || node.parentNode == el){
13064 var p = node.parentNode;
13065 while(p && p != el){
13066 if(p.parentNode == el){
13075 onClick : function(e){
13076 var item = this.findItemFromChild(e.getTarget());
13078 var index = this.indexOf(item);
13079 if(this.onItemClick(item, index, e) !== false){
13080 this.fireEvent("click", this, index, item, e);
13083 this.clearSelections();
13088 onContextMenu : function(e){
13089 var item = this.findItemFromChild(e.getTarget());
13091 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13096 onDblClick : function(e){
13097 var item = this.findItemFromChild(e.getTarget());
13099 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13103 onItemClick : function(item, index, e)
13105 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13108 if (this.toggleSelect) {
13109 var m = this.isSelected(item) ? 'unselect' : 'select';
13112 _t[m](item, true, false);
13115 if(this.multiSelect || this.singleSelect){
13116 if(this.multiSelect && e.shiftKey && this.lastSelection){
13117 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13119 this.select(item, this.multiSelect && e.ctrlKey);
13120 this.lastSelection = item;
13123 if(!this.tickable){
13124 e.preventDefault();
13132 * Get the number of selected nodes.
13135 getSelectionCount : function(){
13136 return this.selections.length;
13140 * Get the currently selected nodes.
13141 * @return {Array} An array of HTMLElements
13143 getSelectedNodes : function(){
13144 return this.selections;
13148 * Get the indexes of the selected nodes.
13151 getSelectedIndexes : function(){
13152 var indexes = [], s = this.selections;
13153 for(var i = 0, len = s.length; i < len; i++){
13154 indexes.push(s[i].nodeIndex);
13160 * Clear all selections
13161 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13163 clearSelections : function(suppressEvent){
13164 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13165 this.cmp.elements = this.selections;
13166 this.cmp.removeClass(this.selectedClass);
13167 this.selections = [];
13168 if(!suppressEvent){
13169 this.fireEvent("selectionchange", this, this.selections);
13175 * Returns true if the passed node is selected
13176 * @param {HTMLElement/Number} node The node or node index
13177 * @return {Boolean}
13179 isSelected : function(node){
13180 var s = this.selections;
13184 node = this.getNode(node);
13185 return s.indexOf(node) !== -1;
13190 * @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
13191 * @param {Boolean} keepExisting (optional) true to keep existing selections
13192 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13194 select : function(nodeInfo, keepExisting, suppressEvent){
13195 if(nodeInfo instanceof Array){
13197 this.clearSelections(true);
13199 for(var i = 0, len = nodeInfo.length; i < len; i++){
13200 this.select(nodeInfo[i], true, true);
13204 var node = this.getNode(nodeInfo);
13205 if(!node || this.isSelected(node)){
13206 return; // already selected.
13209 this.clearSelections(true);
13212 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13213 Roo.fly(node).addClass(this.selectedClass);
13214 this.selections.push(node);
13215 if(!suppressEvent){
13216 this.fireEvent("selectionchange", this, this.selections);
13224 * @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
13225 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13226 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13228 unselect : function(nodeInfo, keepExisting, suppressEvent)
13230 if(nodeInfo instanceof Array){
13231 Roo.each(this.selections, function(s) {
13232 this.unselect(s, nodeInfo);
13236 var node = this.getNode(nodeInfo);
13237 if(!node || !this.isSelected(node)){
13238 //Roo.log("not selected");
13239 return; // not selected.
13243 Roo.each(this.selections, function(s) {
13245 Roo.fly(node).removeClass(this.selectedClass);
13252 this.selections= ns;
13253 this.fireEvent("selectionchange", this, this.selections);
13257 * Gets a template node.
13258 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13259 * @return {HTMLElement} The node or null if it wasn't found
13261 getNode : function(nodeInfo){
13262 if(typeof nodeInfo == "string"){
13263 return document.getElementById(nodeInfo);
13264 }else if(typeof nodeInfo == "number"){
13265 return this.nodes[nodeInfo];
13271 * Gets a range template nodes.
13272 * @param {Number} startIndex
13273 * @param {Number} endIndex
13274 * @return {Array} An array of nodes
13276 getNodes : function(start, end){
13277 var ns = this.nodes;
13278 start = start || 0;
13279 end = typeof end == "undefined" ? ns.length - 1 : end;
13282 for(var i = start; i <= end; i++){
13286 for(var i = start; i >= end; i--){
13294 * Finds the index of the passed node
13295 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13296 * @return {Number} The index of the node or -1
13298 indexOf : function(node){
13299 node = this.getNode(node);
13300 if(typeof node.nodeIndex == "number"){
13301 return node.nodeIndex;
13303 var ns = this.nodes;
13304 for(var i = 0, len = ns.length; i < len; i++){
13315 * based on jquery fullcalendar
13319 Roo.bootstrap = Roo.bootstrap || {};
13321 * @class Roo.bootstrap.Calendar
13322 * @extends Roo.bootstrap.Component
13323 * Bootstrap Calendar class
13324 * @cfg {Boolean} loadMask (true|false) default false
13325 * @cfg {Object} header generate the user specific header of the calendar, default false
13328 * Create a new Container
13329 * @param {Object} config The config object
13334 Roo.bootstrap.Calendar = function(config){
13335 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13339 * Fires when a date is selected
13340 * @param {DatePicker} this
13341 * @param {Date} date The selected date
13345 * @event monthchange
13346 * Fires when the displayed month changes
13347 * @param {DatePicker} this
13348 * @param {Date} date The selected month
13350 'monthchange': true,
13352 * @event evententer
13353 * Fires when mouse over an event
13354 * @param {Calendar} this
13355 * @param {event} Event
13357 'evententer': true,
13359 * @event eventleave
13360 * Fires when the mouse leaves an
13361 * @param {Calendar} this
13364 'eventleave': true,
13366 * @event eventclick
13367 * Fires when the mouse click an
13368 * @param {Calendar} this
13377 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13380 * @cfg {Number} startDay
13381 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13389 getAutoCreate : function(){
13392 var fc_button = function(name, corner, style, content ) {
13393 return Roo.apply({},{
13395 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13397 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13400 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13411 style : 'width:100%',
13418 cls : 'fc-header-left',
13420 fc_button('prev', 'left', 'arrow', '‹' ),
13421 fc_button('next', 'right', 'arrow', '›' ),
13422 { tag: 'span', cls: 'fc-header-space' },
13423 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13431 cls : 'fc-header-center',
13435 cls: 'fc-header-title',
13438 html : 'month / year'
13446 cls : 'fc-header-right',
13448 /* fc_button('month', 'left', '', 'month' ),
13449 fc_button('week', '', '', 'week' ),
13450 fc_button('day', 'right', '', 'day' )
13462 header = this.header;
13465 var cal_heads = function() {
13467 // fixme - handle this.
13469 for (var i =0; i < Date.dayNames.length; i++) {
13470 var d = Date.dayNames[i];
13473 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13474 html : d.substring(0,3)
13478 ret[0].cls += ' fc-first';
13479 ret[6].cls += ' fc-last';
13482 var cal_cell = function(n) {
13485 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13490 cls: 'fc-day-number',
13494 cls: 'fc-day-content',
13498 style: 'position: relative;' // height: 17px;
13510 var cal_rows = function() {
13513 for (var r = 0; r < 6; r++) {
13520 for (var i =0; i < Date.dayNames.length; i++) {
13521 var d = Date.dayNames[i];
13522 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13525 row.cn[0].cls+=' fc-first';
13526 row.cn[0].cn[0].style = 'min-height:90px';
13527 row.cn[6].cls+=' fc-last';
13531 ret[0].cls += ' fc-first';
13532 ret[4].cls += ' fc-prev-last';
13533 ret[5].cls += ' fc-last';
13540 cls: 'fc-border-separate',
13541 style : 'width:100%',
13549 cls : 'fc-first fc-last',
13567 cls : 'fc-content',
13568 style : "position: relative;",
13571 cls : 'fc-view fc-view-month fc-grid',
13572 style : 'position: relative',
13573 unselectable : 'on',
13576 cls : 'fc-event-container',
13577 style : 'position:absolute;z-index:8;top:0;left:0;'
13595 initEvents : function()
13598 throw "can not find store for calendar";
13604 style: "text-align:center",
13608 style: "background-color:white;width:50%;margin:250 auto",
13612 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13623 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13625 var size = this.el.select('.fc-content', true).first().getSize();
13626 this.maskEl.setSize(size.width, size.height);
13627 this.maskEl.enableDisplayMode("block");
13628 if(!this.loadMask){
13629 this.maskEl.hide();
13632 this.store = Roo.factory(this.store, Roo.data);
13633 this.store.on('load', this.onLoad, this);
13634 this.store.on('beforeload', this.onBeforeLoad, this);
13638 this.cells = this.el.select('.fc-day',true);
13639 //Roo.log(this.cells);
13640 this.textNodes = this.el.query('.fc-day-number');
13641 this.cells.addClassOnOver('fc-state-hover');
13643 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13644 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13645 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13646 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13648 this.on('monthchange', this.onMonthChange, this);
13650 this.update(new Date().clearTime());
13653 resize : function() {
13654 var sz = this.el.getSize();
13656 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13657 this.el.select('.fc-day-content div',true).setHeight(34);
13662 showPrevMonth : function(e){
13663 this.update(this.activeDate.add("mo", -1));
13665 showToday : function(e){
13666 this.update(new Date().clearTime());
13669 showNextMonth : function(e){
13670 this.update(this.activeDate.add("mo", 1));
13674 showPrevYear : function(){
13675 this.update(this.activeDate.add("y", -1));
13679 showNextYear : function(){
13680 this.update(this.activeDate.add("y", 1));
13685 update : function(date)
13687 var vd = this.activeDate;
13688 this.activeDate = date;
13689 // if(vd && this.el){
13690 // var t = date.getTime();
13691 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13692 // Roo.log('using add remove');
13694 // this.fireEvent('monthchange', this, date);
13696 // this.cells.removeClass("fc-state-highlight");
13697 // this.cells.each(function(c){
13698 // if(c.dateValue == t){
13699 // c.addClass("fc-state-highlight");
13700 // setTimeout(function(){
13701 // try{c.dom.firstChild.focus();}catch(e){}
13711 var days = date.getDaysInMonth();
13713 var firstOfMonth = date.getFirstDateOfMonth();
13714 var startingPos = firstOfMonth.getDay()-this.startDay;
13716 if(startingPos < this.startDay){
13720 var pm = date.add(Date.MONTH, -1);
13721 var prevStart = pm.getDaysInMonth()-startingPos;
13723 this.cells = this.el.select('.fc-day',true);
13724 this.textNodes = this.el.query('.fc-day-number');
13725 this.cells.addClassOnOver('fc-state-hover');
13727 var cells = this.cells.elements;
13728 var textEls = this.textNodes;
13730 Roo.each(cells, function(cell){
13731 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13734 days += startingPos;
13736 // convert everything to numbers so it's fast
13737 var day = 86400000;
13738 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13741 //Roo.log(prevStart);
13743 var today = new Date().clearTime().getTime();
13744 var sel = date.clearTime().getTime();
13745 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13746 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13747 var ddMatch = this.disabledDatesRE;
13748 var ddText = this.disabledDatesText;
13749 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13750 var ddaysText = this.disabledDaysText;
13751 var format = this.format;
13753 var setCellClass = function(cal, cell){
13757 //Roo.log('set Cell Class');
13759 var t = d.getTime();
13763 cell.dateValue = t;
13765 cell.className += " fc-today";
13766 cell.className += " fc-state-highlight";
13767 cell.title = cal.todayText;
13770 // disable highlight in other month..
13771 //cell.className += " fc-state-highlight";
13776 cell.className = " fc-state-disabled";
13777 cell.title = cal.minText;
13781 cell.className = " fc-state-disabled";
13782 cell.title = cal.maxText;
13786 if(ddays.indexOf(d.getDay()) != -1){
13787 cell.title = ddaysText;
13788 cell.className = " fc-state-disabled";
13791 if(ddMatch && format){
13792 var fvalue = d.dateFormat(format);
13793 if(ddMatch.test(fvalue)){
13794 cell.title = ddText.replace("%0", fvalue);
13795 cell.className = " fc-state-disabled";
13799 if (!cell.initialClassName) {
13800 cell.initialClassName = cell.dom.className;
13803 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13808 for(; i < startingPos; i++) {
13809 textEls[i].innerHTML = (++prevStart);
13810 d.setDate(d.getDate()+1);
13812 cells[i].className = "fc-past fc-other-month";
13813 setCellClass(this, cells[i]);
13818 for(; i < days; i++){
13819 intDay = i - startingPos + 1;
13820 textEls[i].innerHTML = (intDay);
13821 d.setDate(d.getDate()+1);
13823 cells[i].className = ''; // "x-date-active";
13824 setCellClass(this, cells[i]);
13828 for(; i < 42; i++) {
13829 textEls[i].innerHTML = (++extraDays);
13830 d.setDate(d.getDate()+1);
13832 cells[i].className = "fc-future fc-other-month";
13833 setCellClass(this, cells[i]);
13836 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13838 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13840 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13841 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13843 if(totalRows != 6){
13844 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13845 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13848 this.fireEvent('monthchange', this, date);
13852 if(!this.internalRender){
13853 var main = this.el.dom.firstChild;
13854 var w = main.offsetWidth;
13855 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13856 Roo.fly(main).setWidth(w);
13857 this.internalRender = true;
13858 // opera does not respect the auto grow header center column
13859 // then, after it gets a width opera refuses to recalculate
13860 // without a second pass
13861 if(Roo.isOpera && !this.secondPass){
13862 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13863 this.secondPass = true;
13864 this.update.defer(10, this, [date]);
13871 findCell : function(dt) {
13872 dt = dt.clearTime().getTime();
13874 this.cells.each(function(c){
13875 //Roo.log("check " +c.dateValue + '?=' + dt);
13876 if(c.dateValue == dt){
13886 findCells : function(ev) {
13887 var s = ev.start.clone().clearTime().getTime();
13889 var e= ev.end.clone().clearTime().getTime();
13892 this.cells.each(function(c){
13893 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13895 if(c.dateValue > e){
13898 if(c.dateValue < s){
13907 // findBestRow: function(cells)
13911 // for (var i =0 ; i < cells.length;i++) {
13912 // ret = Math.max(cells[i].rows || 0,ret);
13919 addItem : function(ev)
13921 // look for vertical location slot in
13922 var cells = this.findCells(ev);
13924 // ev.row = this.findBestRow(cells);
13926 // work out the location.
13930 for(var i =0; i < cells.length; i++) {
13932 cells[i].row = cells[0].row;
13935 cells[i].row = cells[i].row + 1;
13945 if (crow.start.getY() == cells[i].getY()) {
13947 crow.end = cells[i];
13964 cells[0].events.push(ev);
13966 this.calevents.push(ev);
13969 clearEvents: function() {
13971 if(!this.calevents){
13975 Roo.each(this.cells.elements, function(c){
13981 Roo.each(this.calevents, function(e) {
13982 Roo.each(e.els, function(el) {
13983 el.un('mouseenter' ,this.onEventEnter, this);
13984 el.un('mouseleave' ,this.onEventLeave, this);
13989 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13995 renderEvents: function()
13999 this.cells.each(function(c) {
14008 if(c.row != c.events.length){
14009 r = 4 - (4 - (c.row - c.events.length));
14012 c.events = ev.slice(0, r);
14013 c.more = ev.slice(r);
14015 if(c.more.length && c.more.length == 1){
14016 c.events.push(c.more.pop());
14019 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14023 this.cells.each(function(c) {
14025 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14028 for (var e = 0; e < c.events.length; e++){
14029 var ev = c.events[e];
14030 var rows = ev.rows;
14032 for(var i = 0; i < rows.length; i++) {
14034 // how many rows should it span..
14037 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14038 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14040 unselectable : "on",
14043 cls: 'fc-event-inner',
14047 // cls: 'fc-event-time',
14048 // html : cells.length > 1 ? '' : ev.time
14052 cls: 'fc-event-title',
14053 html : String.format('{0}', ev.title)
14060 cls: 'ui-resizable-handle ui-resizable-e',
14061 html : '  '
14068 cfg.cls += ' fc-event-start';
14070 if ((i+1) == rows.length) {
14071 cfg.cls += ' fc-event-end';
14074 var ctr = _this.el.select('.fc-event-container',true).first();
14075 var cg = ctr.createChild(cfg);
14077 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14078 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14080 var r = (c.more.length) ? 1 : 0;
14081 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14082 cg.setWidth(ebox.right - sbox.x -2);
14084 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14085 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14086 cg.on('click', _this.onEventClick, _this, ev);
14097 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14098 style : 'position: absolute',
14099 unselectable : "on",
14102 cls: 'fc-event-inner',
14106 cls: 'fc-event-title',
14114 cls: 'ui-resizable-handle ui-resizable-e',
14115 html : '  '
14121 var ctr = _this.el.select('.fc-event-container',true).first();
14122 var cg = ctr.createChild(cfg);
14124 var sbox = c.select('.fc-day-content',true).first().getBox();
14125 var ebox = c.select('.fc-day-content',true).first().getBox();
14127 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14128 cg.setWidth(ebox.right - sbox.x -2);
14130 cg.on('click', _this.onMoreEventClick, _this, c.more);
14140 onEventEnter: function (e, el,event,d) {
14141 this.fireEvent('evententer', this, el, event);
14144 onEventLeave: function (e, el,event,d) {
14145 this.fireEvent('eventleave', this, el, event);
14148 onEventClick: function (e, el,event,d) {
14149 this.fireEvent('eventclick', this, el, event);
14152 onMonthChange: function () {
14156 onMoreEventClick: function(e, el, more)
14160 this.calpopover.placement = 'right';
14161 this.calpopover.setTitle('More');
14163 this.calpopover.setContent('');
14165 var ctr = this.calpopover.el.select('.popover-content', true).first();
14167 Roo.each(more, function(m){
14169 cls : 'fc-event-hori fc-event-draggable',
14172 var cg = ctr.createChild(cfg);
14174 cg.on('click', _this.onEventClick, _this, m);
14177 this.calpopover.show(el);
14182 onLoad: function ()
14184 this.calevents = [];
14187 if(this.store.getCount() > 0){
14188 this.store.data.each(function(d){
14191 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14192 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14193 time : d.data.start_time,
14194 title : d.data.title,
14195 description : d.data.description,
14196 venue : d.data.venue
14201 this.renderEvents();
14203 if(this.calevents.length && this.loadMask){
14204 this.maskEl.hide();
14208 onBeforeLoad: function()
14210 this.clearEvents();
14212 this.maskEl.show();
14226 * @class Roo.bootstrap.Popover
14227 * @extends Roo.bootstrap.Component
14228 * Bootstrap Popover class
14229 * @cfg {String} html contents of the popover (or false to use children..)
14230 * @cfg {String} title of popover (or false to hide)
14231 * @cfg {String} placement how it is placed
14232 * @cfg {String} trigger click || hover (or false to trigger manually)
14233 * @cfg {String} over what (parent or false to trigger manually.)
14234 * @cfg {Number} delay - delay before showing
14237 * Create a new Popover
14238 * @param {Object} config The config object
14241 Roo.bootstrap.Popover = function(config){
14242 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14245 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14247 title: 'Fill in a title',
14250 placement : 'right',
14251 trigger : 'hover', // hover
14257 can_build_overlaid : false,
14259 getChildContainer : function()
14261 return this.el.select('.popover-content',true).first();
14264 getAutoCreate : function(){
14265 Roo.log('make popover?');
14267 cls : 'popover roo-dynamic',
14268 style: 'display:block',
14274 cls : 'popover-inner',
14278 cls: 'popover-title',
14282 cls : 'popover-content',
14293 setTitle: function(str)
14295 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14297 setContent: function(str)
14299 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14301 // as it get's added to the bottom of the page.
14302 onRender : function(ct, position)
14304 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14306 var cfg = Roo.apply({}, this.getAutoCreate());
14310 cfg.cls += ' ' + this.cls;
14313 cfg.style = this.style;
14315 Roo.log("adding to ")
14316 this.el = Roo.get(document.body).createChild(cfg, position);
14322 initEvents : function()
14324 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14325 this.el.enableDisplayMode('block');
14327 if (this.over === false) {
14330 if (this.triggers === false) {
14333 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14334 var triggers = this.trigger ? this.trigger.split(' ') : [];
14335 Roo.each(triggers, function(trigger) {
14337 if (trigger == 'click') {
14338 on_el.on('click', this.toggle, this);
14339 } else if (trigger != 'manual') {
14340 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14341 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14343 on_el.on(eventIn ,this.enter, this);
14344 on_el.on(eventOut, this.leave, this);
14355 toggle : function () {
14356 this.hoverState == 'in' ? this.leave() : this.enter();
14359 enter : function () {
14362 clearTimeout(this.timeout);
14364 this.hoverState = 'in';
14366 if (!this.delay || !this.delay.show) {
14371 this.timeout = setTimeout(function () {
14372 if (_t.hoverState == 'in') {
14375 }, this.delay.show)
14377 leave : function() {
14378 clearTimeout(this.timeout);
14380 this.hoverState = 'out';
14382 if (!this.delay || !this.delay.hide) {
14387 this.timeout = setTimeout(function () {
14388 if (_t.hoverState == 'out') {
14391 }, this.delay.hide)
14394 show : function (on_el)
14397 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14400 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14401 if (this.html !== false) {
14402 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14404 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14405 if (!this.title.length) {
14406 this.el.select('.popover-title',true).hide();
14409 var placement = typeof this.placement == 'function' ?
14410 this.placement.call(this, this.el, on_el) :
14413 var autoToken = /\s?auto?\s?/i;
14414 var autoPlace = autoToken.test(placement);
14416 placement = placement.replace(autoToken, '') || 'top';
14420 //this.el.setXY([0,0]);
14422 this.el.dom.style.display='block';
14423 this.el.addClass(placement);
14425 //this.el.appendTo(on_el);
14427 var p = this.getPosition();
14428 var box = this.el.getBox();
14433 var align = Roo.bootstrap.Popover.alignment[placement];
14434 this.el.alignTo(on_el, align[0],align[1]);
14435 //var arrow = this.el.select('.arrow',true).first();
14436 //arrow.set(align[2],
14438 this.el.addClass('in');
14439 this.hoverState = null;
14441 if (this.el.hasClass('fade')) {
14448 this.el.setXY([0,0]);
14449 this.el.removeClass('in');
14456 Roo.bootstrap.Popover.alignment = {
14457 'left' : ['r-l', [-10,0], 'right'],
14458 'right' : ['l-r', [10,0], 'left'],
14459 'bottom' : ['t-b', [0,10], 'top'],
14460 'top' : [ 'b-t', [0,-10], 'bottom']
14471 * @class Roo.bootstrap.Progress
14472 * @extends Roo.bootstrap.Component
14473 * Bootstrap Progress class
14474 * @cfg {Boolean} striped striped of the progress bar
14475 * @cfg {Boolean} active animated of the progress bar
14479 * Create a new Progress
14480 * @param {Object} config The config object
14483 Roo.bootstrap.Progress = function(config){
14484 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14487 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14492 getAutoCreate : function(){
14500 cfg.cls += ' progress-striped';
14504 cfg.cls += ' active';
14523 * @class Roo.bootstrap.ProgressBar
14524 * @extends Roo.bootstrap.Component
14525 * Bootstrap ProgressBar class
14526 * @cfg {Number} aria_valuenow aria-value now
14527 * @cfg {Number} aria_valuemin aria-value min
14528 * @cfg {Number} aria_valuemax aria-value max
14529 * @cfg {String} label label for the progress bar
14530 * @cfg {String} panel (success | info | warning | danger )
14531 * @cfg {String} role role of the progress bar
14532 * @cfg {String} sr_only text
14536 * Create a new ProgressBar
14537 * @param {Object} config The config object
14540 Roo.bootstrap.ProgressBar = function(config){
14541 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14544 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14548 aria_valuemax : 100,
14554 getAutoCreate : function()
14559 cls: 'progress-bar',
14560 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14572 cfg.role = this.role;
14575 if(this.aria_valuenow){
14576 cfg['aria-valuenow'] = this.aria_valuenow;
14579 if(this.aria_valuemin){
14580 cfg['aria-valuemin'] = this.aria_valuemin;
14583 if(this.aria_valuemax){
14584 cfg['aria-valuemax'] = this.aria_valuemax;
14587 if(this.label && !this.sr_only){
14588 cfg.html = this.label;
14592 cfg.cls += ' progress-bar-' + this.panel;
14598 update : function(aria_valuenow)
14600 this.aria_valuenow = aria_valuenow;
14602 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14617 * @class Roo.bootstrap.TabGroup
14618 * @extends Roo.bootstrap.Column
14619 * Bootstrap Column class
14620 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14621 * @cfg {Boolean} carousel true to make the group behave like a carousel
14622 * @cfg {Number} bullets show the panel pointer.. default 0
14623 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14624 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14625 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14628 * Create a new TabGroup
14629 * @param {Object} config The config object
14632 Roo.bootstrap.TabGroup = function(config){
14633 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14635 this.navId = Roo.id();
14638 Roo.bootstrap.TabGroup.register(this);
14642 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14645 transition : false,
14650 slideOnTouch : false,
14652 getAutoCreate : function()
14654 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14656 cfg.cls += ' tab-content';
14658 Roo.log('get auto create...............');
14660 if (this.carousel) {
14661 cfg.cls += ' carousel slide';
14664 cls : 'carousel-inner'
14667 if(this.bullets > 0 && !Roo.isTouch){
14670 cls : 'carousel-bullets',
14674 if(this.bullets_cls){
14675 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14678 for (var i = 0; i < this.bullets; i++){
14680 cls : 'bullet bullet-' + i
14688 cfg.cn[0].cn = bullets;
14695 initEvents: function()
14697 Roo.log('-------- init events on tab group ---------');
14699 if(this.bullets > 0 && !Roo.isTouch){
14705 if(Roo.isTouch && this.slideOnTouch){
14706 this.el.on("touchstart", this.onTouchStart, this);
14709 if(this.autoslide){
14712 this.slideFn = window.setInterval(function() {
14713 _this.showPanelNext();
14719 onTouchStart : function(e, el, o)
14721 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14725 this.showPanelNext();
14728 getChildContainer : function()
14730 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14734 * register a Navigation item
14735 * @param {Roo.bootstrap.NavItem} the navitem to add
14737 register : function(item)
14739 this.tabs.push( item);
14740 item.navId = this.navId; // not really needed..
14744 getActivePanel : function()
14747 Roo.each(this.tabs, function(t) {
14757 getPanelByName : function(n)
14760 Roo.each(this.tabs, function(t) {
14761 if (t.tabId == n) {
14769 indexOfPanel : function(p)
14772 Roo.each(this.tabs, function(t,i) {
14773 if (t.tabId == p.tabId) {
14782 * show a specific panel
14783 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14784 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14786 showPanel : function (pan)
14788 if(this.transition){
14789 Roo.log("waiting for the transitionend");
14793 if (typeof(pan) == 'number') {
14794 pan = this.tabs[pan];
14796 if (typeof(pan) == 'string') {
14797 pan = this.getPanelByName(pan);
14799 if (pan.tabId == this.getActivePanel().tabId) {
14802 var cur = this.getActivePanel();
14804 if (false === cur.fireEvent('beforedeactivate')) {
14808 if(this.bullets > 0 && !Roo.isTouch){
14809 this.setActiveBullet(this.indexOfPanel(pan));
14812 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14814 this.transition = true;
14815 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14816 var lr = dir == 'next' ? 'left' : 'right';
14817 pan.el.addClass(dir); // or prev
14818 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14819 cur.el.addClass(lr); // or right
14820 pan.el.addClass(lr);
14823 cur.el.on('transitionend', function() {
14824 Roo.log("trans end?");
14826 pan.el.removeClass([lr,dir]);
14827 pan.setActive(true);
14829 cur.el.removeClass([lr]);
14830 cur.setActive(false);
14832 _this.transition = false;
14834 }, this, { single: true } );
14839 cur.setActive(false);
14840 pan.setActive(true);
14845 showPanelNext : function()
14847 var i = this.indexOfPanel(this.getActivePanel());
14849 if (i >= this.tabs.length - 1 && !this.autoslide) {
14853 if (i >= this.tabs.length - 1 && this.autoslide) {
14857 this.showPanel(this.tabs[i+1]);
14860 showPanelPrev : function()
14862 var i = this.indexOfPanel(this.getActivePanel());
14864 if (i < 1 && !this.autoslide) {
14868 if (i < 1 && this.autoslide) {
14869 i = this.tabs.length;
14872 this.showPanel(this.tabs[i-1]);
14875 initBullet : function()
14883 for (var i = 0; i < this.bullets; i++){
14884 var bullet = this.el.select('.bullet-' + i, true).first();
14890 bullet.on('click', (function(e, el, o, ii, t){
14892 e.preventDefault();
14894 _this.showPanel(ii);
14896 if(_this.autoslide && _this.slideFn){
14897 clearInterval(_this.slideFn);
14898 _this.slideFn = window.setInterval(function() {
14899 _this.showPanelNext();
14903 }).createDelegate(this, [i, bullet], true));
14907 setActiveBullet : function(i)
14913 Roo.each(this.el.select('.bullet', true).elements, function(el){
14914 el.removeClass('selected');
14917 var bullet = this.el.select('.bullet-' + i, true).first();
14923 bullet.addClass('selected');
14934 Roo.apply(Roo.bootstrap.TabGroup, {
14938 * register a Navigation Group
14939 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14941 register : function(navgrp)
14943 this.groups[navgrp.navId] = navgrp;
14947 * fetch a Navigation Group based on the navigation ID
14948 * if one does not exist , it will get created.
14949 * @param {string} the navgroup to add
14950 * @returns {Roo.bootstrap.NavGroup} the navgroup
14952 get: function(navId) {
14953 if (typeof(this.groups[navId]) == 'undefined') {
14954 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14956 return this.groups[navId] ;
14971 * @class Roo.bootstrap.TabPanel
14972 * @extends Roo.bootstrap.Component
14973 * Bootstrap TabPanel class
14974 * @cfg {Boolean} active panel active
14975 * @cfg {String} html panel content
14976 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14977 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14981 * Create a new TabPanel
14982 * @param {Object} config The config object
14985 Roo.bootstrap.TabPanel = function(config){
14986 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14990 * Fires when the active status changes
14991 * @param {Roo.bootstrap.TabPanel} this
14992 * @param {Boolean} state the new state
14997 * @event beforedeactivate
14998 * Fires before a tab is de-activated - can be used to do validation on a form.
14999 * @param {Roo.bootstrap.TabPanel} this
15000 * @return {Boolean} false if there is an error
15003 'beforedeactivate': true
15006 this.tabId = this.tabId || Roo.id();
15010 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15017 getAutoCreate : function(){
15020 // item is needed for carousel - not sure if it has any effect otherwise
15021 cls: 'tab-pane item',
15022 html: this.html || ''
15026 cfg.cls += ' active';
15030 cfg.tabId = this.tabId;
15037 initEvents: function()
15039 Roo.log('-------- init events on tab panel ---------');
15041 var p = this.parent();
15042 this.navId = this.navId || p.navId;
15044 if (typeof(this.navId) != 'undefined') {
15045 // not really needed.. but just in case.. parent should be a NavGroup.
15046 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15047 Roo.log(['register', tg, this]);
15050 var i = tg.tabs.length - 1;
15052 if(this.active && tg.bullets > 0 && i < tg.bullets){
15053 tg.setActiveBullet(i);
15060 onRender : function(ct, position)
15062 // Roo.log("Call onRender: " + this.xtype);
15064 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15072 setActive: function(state)
15074 Roo.log("panel - set active " + this.tabId + "=" + state);
15076 this.active = state;
15078 this.el.removeClass('active');
15080 } else if (!this.el.hasClass('active')) {
15081 this.el.addClass('active');
15084 this.fireEvent('changed', this, state);
15101 * @class Roo.bootstrap.DateField
15102 * @extends Roo.bootstrap.Input
15103 * Bootstrap DateField class
15104 * @cfg {Number} weekStart default 0
15105 * @cfg {String} viewMode default empty, (months|years)
15106 * @cfg {String} minViewMode default empty, (months|years)
15107 * @cfg {Number} startDate default -Infinity
15108 * @cfg {Number} endDate default Infinity
15109 * @cfg {Boolean} todayHighlight default false
15110 * @cfg {Boolean} todayBtn default false
15111 * @cfg {Boolean} calendarWeeks default false
15112 * @cfg {Object} daysOfWeekDisabled default empty
15113 * @cfg {Boolean} singleMode default false (true | false)
15115 * @cfg {Boolean} keyboardNavigation default true
15116 * @cfg {String} language default en
15119 * Create a new DateField
15120 * @param {Object} config The config object
15123 Roo.bootstrap.DateField = function(config){
15124 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15128 * Fires when this field show.
15129 * @param {Roo.bootstrap.DateField} this
15130 * @param {Mixed} date The date value
15135 * Fires when this field hide.
15136 * @param {Roo.bootstrap.DateField} this
15137 * @param {Mixed} date The date value
15142 * Fires when select a date.
15143 * @param {Roo.bootstrap.DateField} this
15144 * @param {Mixed} date The date value
15150 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15153 * @cfg {String} format
15154 * The default date format string which can be overriden for localization support. The format must be
15155 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15159 * @cfg {String} altFormats
15160 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15161 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15163 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15171 todayHighlight : false,
15177 keyboardNavigation: true,
15179 calendarWeeks: false,
15181 startDate: -Infinity,
15185 daysOfWeekDisabled: [],
15189 singleMode : false,
15191 UTCDate: function()
15193 return new Date(Date.UTC.apply(Date, arguments));
15196 UTCToday: function()
15198 var today = new Date();
15199 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15202 getDate: function() {
15203 var d = this.getUTCDate();
15204 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15207 getUTCDate: function() {
15211 setDate: function(d) {
15212 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15215 setUTCDate: function(d) {
15217 this.setValue(this.formatDate(this.date));
15220 onRender: function(ct, position)
15223 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15225 this.language = this.language || 'en';
15226 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15227 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15229 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15230 this.format = this.format || 'm/d/y';
15231 this.isInline = false;
15232 this.isInput = true;
15233 this.component = this.el.select('.add-on', true).first() || false;
15234 this.component = (this.component && this.component.length === 0) ? false : this.component;
15235 this.hasInput = this.component && this.inputEL().length;
15237 if (typeof(this.minViewMode === 'string')) {
15238 switch (this.minViewMode) {
15240 this.minViewMode = 1;
15243 this.minViewMode = 2;
15246 this.minViewMode = 0;
15251 if (typeof(this.viewMode === 'string')) {
15252 switch (this.viewMode) {
15265 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15267 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15269 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15271 this.picker().on('mousedown', this.onMousedown, this);
15272 this.picker().on('click', this.onClick, this);
15274 this.picker().addClass('datepicker-dropdown');
15276 this.startViewMode = this.viewMode;
15278 if(this.singleMode){
15279 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15280 v.setVisibilityMode(Roo.Element.DISPLAY)
15284 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15285 v.setStyle('width', '189px');
15289 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15290 if(!this.calendarWeeks){
15295 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15296 v.attr('colspan', function(i, val){
15297 return parseInt(val) + 1;
15302 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15304 this.setStartDate(this.startDate);
15305 this.setEndDate(this.endDate);
15307 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15314 if(this.isInline) {
15319 picker : function()
15321 return this.pickerEl;
15322 // return this.el.select('.datepicker', true).first();
15325 fillDow: function()
15327 var dowCnt = this.weekStart;
15336 if(this.calendarWeeks){
15344 while (dowCnt < this.weekStart + 7) {
15348 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15352 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15355 fillMonths: function()
15358 var months = this.picker().select('>.datepicker-months td', true).first();
15360 months.dom.innerHTML = '';
15366 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15369 months.createChild(month);
15376 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;
15378 if (this.date < this.startDate) {
15379 this.viewDate = new Date(this.startDate);
15380 } else if (this.date > this.endDate) {
15381 this.viewDate = new Date(this.endDate);
15383 this.viewDate = new Date(this.date);
15391 var d = new Date(this.viewDate),
15392 year = d.getUTCFullYear(),
15393 month = d.getUTCMonth(),
15394 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15395 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15396 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15397 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15398 currentDate = this.date && this.date.valueOf(),
15399 today = this.UTCToday();
15401 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15403 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15405 // this.picker.select('>tfoot th.today').
15406 // .text(dates[this.language].today)
15407 // .toggle(this.todayBtn !== false);
15409 this.updateNavArrows();
15412 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15414 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15416 prevMonth.setUTCDate(day);
15418 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15420 var nextMonth = new Date(prevMonth);
15422 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15424 nextMonth = nextMonth.valueOf();
15426 var fillMonths = false;
15428 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15430 while(prevMonth.valueOf() < nextMonth) {
15433 if (prevMonth.getUTCDay() === this.weekStart) {
15435 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15443 if(this.calendarWeeks){
15444 // ISO 8601: First week contains first thursday.
15445 // ISO also states week starts on Monday, but we can be more abstract here.
15447 // Start of current week: based on weekstart/current date
15448 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15449 // Thursday of this week
15450 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15451 // First Thursday of year, year from thursday
15452 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15453 // Calendar week: ms between thursdays, div ms per day, div 7 days
15454 calWeek = (th - yth) / 864e5 / 7 + 1;
15456 fillMonths.cn.push({
15464 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15466 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15469 if (this.todayHighlight &&
15470 prevMonth.getUTCFullYear() == today.getFullYear() &&
15471 prevMonth.getUTCMonth() == today.getMonth() &&
15472 prevMonth.getUTCDate() == today.getDate()) {
15473 clsName += ' today';
15476 if (currentDate && prevMonth.valueOf() === currentDate) {
15477 clsName += ' active';
15480 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15481 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15482 clsName += ' disabled';
15485 fillMonths.cn.push({
15487 cls: 'day ' + clsName,
15488 html: prevMonth.getDate()
15491 prevMonth.setDate(prevMonth.getDate()+1);
15494 var currentYear = this.date && this.date.getUTCFullYear();
15495 var currentMonth = this.date && this.date.getUTCMonth();
15497 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15499 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15500 v.removeClass('active');
15502 if(currentYear === year && k === currentMonth){
15503 v.addClass('active');
15506 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15507 v.addClass('disabled');
15513 year = parseInt(year/10, 10) * 10;
15515 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15517 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15520 for (var i = -1; i < 11; i++) {
15521 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15523 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15531 showMode: function(dir)
15534 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15537 Roo.each(this.picker().select('>div',true).elements, function(v){
15538 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15541 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15546 if(this.isInline) return;
15548 this.picker().removeClass(['bottom', 'top']);
15550 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15552 * place to the top of element!
15556 this.picker().addClass('top');
15557 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15562 this.picker().addClass('bottom');
15564 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15567 parseDate : function(value)
15569 if(!value || value instanceof Date){
15572 var v = Date.parseDate(value, this.format);
15573 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15574 v = Date.parseDate(value, 'Y-m-d');
15576 if(!v && this.altFormats){
15577 if(!this.altFormatsArray){
15578 this.altFormatsArray = this.altFormats.split("|");
15580 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15581 v = Date.parseDate(value, this.altFormatsArray[i]);
15587 formatDate : function(date, fmt)
15589 return (!date || !(date instanceof Date)) ?
15590 date : date.dateFormat(fmt || this.format);
15593 onFocus : function()
15595 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15599 onBlur : function()
15601 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15603 var d = this.inputEl().getValue();
15612 this.picker().show();
15616 this.fireEvent('show', this, this.date);
15621 if(this.isInline) return;
15622 this.picker().hide();
15623 this.viewMode = this.startViewMode;
15626 this.fireEvent('hide', this, this.date);
15630 onMousedown: function(e)
15632 e.stopPropagation();
15633 e.preventDefault();
15638 Roo.bootstrap.DateField.superclass.keyup.call(this);
15642 setValue: function(v)
15645 // v can be a string or a date..
15648 var d = new Date(this.parseDate(v) ).clearTime();
15650 if(isNaN(d.getTime())){
15651 this.date = this.viewDate = '';
15652 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15656 v = this.formatDate(d);
15658 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15660 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15664 this.fireEvent('select', this, this.date);
15668 getValue: function()
15670 return this.formatDate(this.date);
15673 fireKey: function(e)
15675 if (!this.picker().isVisible()){
15676 if (e.keyCode == 27) // allow escape to hide and re-show picker
15681 var dateChanged = false,
15683 newDate, newViewDate;
15688 e.preventDefault();
15692 if (!this.keyboardNavigation) break;
15693 dir = e.keyCode == 37 ? -1 : 1;
15696 newDate = this.moveYear(this.date, dir);
15697 newViewDate = this.moveYear(this.viewDate, dir);
15698 } else if (e.shiftKey){
15699 newDate = this.moveMonth(this.date, dir);
15700 newViewDate = this.moveMonth(this.viewDate, dir);
15702 newDate = new Date(this.date);
15703 newDate.setUTCDate(this.date.getUTCDate() + dir);
15704 newViewDate = new Date(this.viewDate);
15705 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15707 if (this.dateWithinRange(newDate)){
15708 this.date = newDate;
15709 this.viewDate = newViewDate;
15710 this.setValue(this.formatDate(this.date));
15712 e.preventDefault();
15713 dateChanged = true;
15718 if (!this.keyboardNavigation) break;
15719 dir = e.keyCode == 38 ? -1 : 1;
15721 newDate = this.moveYear(this.date, dir);
15722 newViewDate = this.moveYear(this.viewDate, dir);
15723 } else if (e.shiftKey){
15724 newDate = this.moveMonth(this.date, dir);
15725 newViewDate = this.moveMonth(this.viewDate, dir);
15727 newDate = new Date(this.date);
15728 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15729 newViewDate = new Date(this.viewDate);
15730 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15732 if (this.dateWithinRange(newDate)){
15733 this.date = newDate;
15734 this.viewDate = newViewDate;
15735 this.setValue(this.formatDate(this.date));
15737 e.preventDefault();
15738 dateChanged = true;
15742 this.setValue(this.formatDate(this.date));
15744 e.preventDefault();
15747 this.setValue(this.formatDate(this.date));
15761 onClick: function(e)
15763 e.stopPropagation();
15764 e.preventDefault();
15766 var target = e.getTarget();
15768 if(target.nodeName.toLowerCase() === 'i'){
15769 target = Roo.get(target).dom.parentNode;
15772 var nodeName = target.nodeName;
15773 var className = target.className;
15774 var html = target.innerHTML;
15775 //Roo.log(nodeName);
15777 switch(nodeName.toLowerCase()) {
15779 switch(className) {
15785 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15786 switch(this.viewMode){
15788 this.viewDate = this.moveMonth(this.viewDate, dir);
15792 this.viewDate = this.moveYear(this.viewDate, dir);
15798 var date = new Date();
15799 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15801 this.setValue(this.formatDate(this.date));
15808 if (className.indexOf('disabled') < 0) {
15809 this.viewDate.setUTCDate(1);
15810 if (className.indexOf('month') > -1) {
15811 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15813 var year = parseInt(html, 10) || 0;
15814 this.viewDate.setUTCFullYear(year);
15818 if(this.singleMode){
15819 this.setValue(this.formatDate(this.viewDate));
15830 //Roo.log(className);
15831 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15832 var day = parseInt(html, 10) || 1;
15833 var year = this.viewDate.getUTCFullYear(),
15834 month = this.viewDate.getUTCMonth();
15836 if (className.indexOf('old') > -1) {
15843 } else if (className.indexOf('new') > -1) {
15851 //Roo.log([year,month,day]);
15852 this.date = this.UTCDate(year, month, day,0,0,0,0);
15853 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15855 //Roo.log(this.formatDate(this.date));
15856 this.setValue(this.formatDate(this.date));
15863 setStartDate: function(startDate)
15865 this.startDate = startDate || -Infinity;
15866 if (this.startDate !== -Infinity) {
15867 this.startDate = this.parseDate(this.startDate);
15870 this.updateNavArrows();
15873 setEndDate: function(endDate)
15875 this.endDate = endDate || Infinity;
15876 if (this.endDate !== Infinity) {
15877 this.endDate = this.parseDate(this.endDate);
15880 this.updateNavArrows();
15883 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15885 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15886 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15887 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15889 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15890 return parseInt(d, 10);
15893 this.updateNavArrows();
15896 updateNavArrows: function()
15898 if(this.singleMode){
15902 var d = new Date(this.viewDate),
15903 year = d.getUTCFullYear(),
15904 month = d.getUTCMonth();
15906 Roo.each(this.picker().select('.prev', true).elements, function(v){
15908 switch (this.viewMode) {
15911 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15917 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15924 Roo.each(this.picker().select('.next', true).elements, function(v){
15926 switch (this.viewMode) {
15929 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15935 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15943 moveMonth: function(date, dir)
15945 if (!dir) return date;
15946 var new_date = new Date(date.valueOf()),
15947 day = new_date.getUTCDate(),
15948 month = new_date.getUTCMonth(),
15949 mag = Math.abs(dir),
15951 dir = dir > 0 ? 1 : -1;
15954 // If going back one month, make sure month is not current month
15955 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15957 return new_date.getUTCMonth() == month;
15959 // If going forward one month, make sure month is as expected
15960 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15962 return new_date.getUTCMonth() != new_month;
15964 new_month = month + dir;
15965 new_date.setUTCMonth(new_month);
15966 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15967 if (new_month < 0 || new_month > 11)
15968 new_month = (new_month + 12) % 12;
15970 // For magnitudes >1, move one month at a time...
15971 for (var i=0; i<mag; i++)
15972 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15973 new_date = this.moveMonth(new_date, dir);
15974 // ...then reset the day, keeping it in the new month
15975 new_month = new_date.getUTCMonth();
15976 new_date.setUTCDate(day);
15978 return new_month != new_date.getUTCMonth();
15981 // Common date-resetting loop -- if date is beyond end of month, make it
15984 new_date.setUTCDate(--day);
15985 new_date.setUTCMonth(new_month);
15990 moveYear: function(date, dir)
15992 return this.moveMonth(date, dir*12);
15995 dateWithinRange: function(date)
15997 return date >= this.startDate && date <= this.endDate;
16003 this.picker().remove();
16008 Roo.apply(Roo.bootstrap.DateField, {
16019 html: '<i class="fa fa-arrow-left"/>'
16029 html: '<i class="fa fa-arrow-right"/>'
16071 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16072 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16073 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16074 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16075 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16088 navFnc: 'FullYear',
16093 navFnc: 'FullYear',
16098 Roo.apply(Roo.bootstrap.DateField, {
16102 cls: 'datepicker dropdown-menu roo-dynamic',
16106 cls: 'datepicker-days',
16110 cls: 'table-condensed',
16112 Roo.bootstrap.DateField.head,
16116 Roo.bootstrap.DateField.footer
16123 cls: 'datepicker-months',
16127 cls: 'table-condensed',
16129 Roo.bootstrap.DateField.head,
16130 Roo.bootstrap.DateField.content,
16131 Roo.bootstrap.DateField.footer
16138 cls: 'datepicker-years',
16142 cls: 'table-condensed',
16144 Roo.bootstrap.DateField.head,
16145 Roo.bootstrap.DateField.content,
16146 Roo.bootstrap.DateField.footer
16165 * @class Roo.bootstrap.TimeField
16166 * @extends Roo.bootstrap.Input
16167 * Bootstrap DateField class
16171 * Create a new TimeField
16172 * @param {Object} config The config object
16175 Roo.bootstrap.TimeField = function(config){
16176 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16180 * Fires when this field show.
16181 * @param {Roo.bootstrap.DateField} thisthis
16182 * @param {Mixed} date The date value
16187 * Fires when this field hide.
16188 * @param {Roo.bootstrap.DateField} this
16189 * @param {Mixed} date The date value
16194 * Fires when select a date.
16195 * @param {Roo.bootstrap.DateField} this
16196 * @param {Mixed} date The date value
16202 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16205 * @cfg {String} format
16206 * The default time format string which can be overriden for localization support. The format must be
16207 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16211 onRender: function(ct, position)
16214 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16216 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16218 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16220 this.pop = this.picker().select('>.datepicker-time',true).first();
16221 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16223 this.picker().on('mousedown', this.onMousedown, this);
16224 this.picker().on('click', this.onClick, this);
16226 this.picker().addClass('datepicker-dropdown');
16231 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16232 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16233 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16234 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16235 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16236 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16240 fireKey: function(e){
16241 if (!this.picker().isVisible()){
16242 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16248 e.preventDefault();
16256 this.onTogglePeriod();
16259 this.onIncrementMinutes();
16262 this.onDecrementMinutes();
16271 onClick: function(e) {
16272 e.stopPropagation();
16273 e.preventDefault();
16276 picker : function()
16278 return this.el.select('.datepicker', true).first();
16281 fillTime: function()
16283 var time = this.pop.select('tbody', true).first();
16285 time.dom.innerHTML = '';
16300 cls: 'hours-up glyphicon glyphicon-chevron-up'
16320 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16341 cls: 'timepicker-hour',
16356 cls: 'timepicker-minute',
16371 cls: 'btn btn-primary period',
16393 cls: 'hours-down glyphicon glyphicon-chevron-down'
16413 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16431 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16438 var hours = this.time.getHours();
16439 var minutes = this.time.getMinutes();
16452 hours = hours - 12;
16456 hours = '0' + hours;
16460 minutes = '0' + minutes;
16463 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16464 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16465 this.pop.select('button', true).first().dom.innerHTML = period;
16471 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16473 var cls = ['bottom'];
16475 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16482 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16487 this.picker().addClass(cls.join('-'));
16491 Roo.each(cls, function(c){
16493 _this.picker().setTop(_this.inputEl().getHeight());
16497 _this.picker().setTop(0 - _this.picker().getHeight());
16502 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16506 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16513 onFocus : function()
16515 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16519 onBlur : function()
16521 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16527 this.picker().show();
16532 this.fireEvent('show', this, this.date);
16537 this.picker().hide();
16540 this.fireEvent('hide', this, this.date);
16543 setTime : function()
16546 this.setValue(this.time.format(this.format));
16548 this.fireEvent('select', this, this.date);
16553 onMousedown: function(e){
16554 e.stopPropagation();
16555 e.preventDefault();
16558 onIncrementHours: function()
16560 Roo.log('onIncrementHours');
16561 this.time = this.time.add(Date.HOUR, 1);
16566 onDecrementHours: function()
16568 Roo.log('onDecrementHours');
16569 this.time = this.time.add(Date.HOUR, -1);
16573 onIncrementMinutes: function()
16575 Roo.log('onIncrementMinutes');
16576 this.time = this.time.add(Date.MINUTE, 1);
16580 onDecrementMinutes: function()
16582 Roo.log('onDecrementMinutes');
16583 this.time = this.time.add(Date.MINUTE, -1);
16587 onTogglePeriod: function()
16589 Roo.log('onTogglePeriod');
16590 this.time = this.time.add(Date.HOUR, 12);
16597 Roo.apply(Roo.bootstrap.TimeField, {
16627 cls: 'btn btn-info ok',
16639 Roo.apply(Roo.bootstrap.TimeField, {
16643 cls: 'datepicker dropdown-menu',
16647 cls: 'datepicker-time',
16651 cls: 'table-condensed',
16653 Roo.bootstrap.TimeField.content,
16654 Roo.bootstrap.TimeField.footer
16673 * @class Roo.bootstrap.MonthField
16674 * @extends Roo.bootstrap.Input
16675 * Bootstrap MonthField class
16677 * @cfg {String} language default en
16680 * Create a new MonthField
16681 * @param {Object} config The config object
16684 Roo.bootstrap.MonthField = function(config){
16685 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16690 * Fires when this field show.
16691 * @param {Roo.bootstrap.MonthField} this
16692 * @param {Mixed} date The date value
16697 * Fires when this field hide.
16698 * @param {Roo.bootstrap.MonthField} this
16699 * @param {Mixed} date The date value
16704 * Fires when select a date.
16705 * @param {Roo.bootstrap.MonthField} this
16706 * @param {String} oldvalue The old value
16707 * @param {String} newvalue The new value
16713 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16715 onRender: function(ct, position)
16718 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16720 this.language = this.language || 'en';
16721 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16722 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16724 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16725 this.isInline = false;
16726 this.isInput = true;
16727 this.component = this.el.select('.add-on', true).first() || false;
16728 this.component = (this.component && this.component.length === 0) ? false : this.component;
16729 this.hasInput = this.component && this.inputEL().length;
16731 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16733 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16735 this.picker().on('mousedown', this.onMousedown, this);
16736 this.picker().on('click', this.onClick, this);
16738 this.picker().addClass('datepicker-dropdown');
16740 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16741 v.setStyle('width', '189px');
16748 if(this.isInline) {
16754 setValue: function(v, suppressEvent)
16756 var o = this.getValue();
16758 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16762 if(suppressEvent !== true){
16763 this.fireEvent('select', this, o, v);
16768 getValue: function()
16773 onClick: function(e)
16775 e.stopPropagation();
16776 e.preventDefault();
16778 var target = e.getTarget();
16780 if(target.nodeName.toLowerCase() === 'i'){
16781 target = Roo.get(target).dom.parentNode;
16784 var nodeName = target.nodeName;
16785 var className = target.className;
16786 var html = target.innerHTML;
16788 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16792 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16794 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16800 picker : function()
16802 return this.pickerEl;
16805 fillMonths: function()
16808 var months = this.picker().select('>.datepicker-months td', true).first();
16810 months.dom.innerHTML = '';
16816 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16819 months.createChild(month);
16828 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16829 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16832 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16833 e.removeClass('active');
16835 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16836 e.addClass('active');
16843 if(this.isInline) return;
16845 this.picker().removeClass(['bottom', 'top']);
16847 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16849 * place to the top of element!
16853 this.picker().addClass('top');
16854 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16859 this.picker().addClass('bottom');
16861 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16864 onFocus : function()
16866 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16870 onBlur : function()
16872 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16874 var d = this.inputEl().getValue();
16883 this.picker().show();
16884 this.picker().select('>.datepicker-months', true).first().show();
16888 this.fireEvent('show', this, this.date);
16893 if(this.isInline) return;
16894 this.picker().hide();
16895 this.fireEvent('hide', this, this.date);
16899 onMousedown: function(e)
16901 e.stopPropagation();
16902 e.preventDefault();
16907 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16911 fireKey: function(e)
16913 if (!this.picker().isVisible()){
16914 if (e.keyCode == 27) // allow escape to hide and re-show picker
16924 e.preventDefault();
16928 dir = e.keyCode == 37 ? -1 : 1;
16930 this.vIndex = this.vIndex + dir;
16932 if(this.vIndex < 0){
16936 if(this.vIndex > 11){
16940 if(isNaN(this.vIndex)){
16944 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16950 dir = e.keyCode == 38 ? -1 : 1;
16952 this.vIndex = this.vIndex + dir * 4;
16954 if(this.vIndex < 0){
16958 if(this.vIndex > 11){
16962 if(isNaN(this.vIndex)){
16966 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16971 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16972 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16976 e.preventDefault();
16979 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16980 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16996 this.picker().remove();
17001 Roo.apply(Roo.bootstrap.MonthField, {
17020 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17021 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17026 Roo.apply(Roo.bootstrap.MonthField, {
17030 cls: 'datepicker dropdown-menu roo-dynamic',
17034 cls: 'datepicker-months',
17038 cls: 'table-condensed',
17040 Roo.bootstrap.DateField.content
17060 * @class Roo.bootstrap.CheckBox
17061 * @extends Roo.bootstrap.Input
17062 * Bootstrap CheckBox class
17064 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17065 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17066 * @cfg {String} boxLabel The text that appears beside the checkbox
17067 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17068 * @cfg {Boolean} checked initnal the element
17069 * @cfg {Boolean} inline inline the element (default false)
17070 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17073 * Create a new CheckBox
17074 * @param {Object} config The config object
17077 Roo.bootstrap.CheckBox = function(config){
17078 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17083 * Fires when the element is checked or unchecked.
17084 * @param {Roo.bootstrap.CheckBox} this This input
17085 * @param {Boolean} checked The new checked value
17092 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17094 inputType: 'checkbox',
17102 getAutoCreate : function()
17104 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17110 cfg.cls = 'form-group ' + this.inputType; //input-group
17113 cfg.cls += ' ' + this.inputType + '-inline';
17119 type : this.inputType,
17120 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17121 cls : 'roo-' + this.inputType, //'form-box',
17122 placeholder : this.placeholder || ''
17126 if (this.weight) { // Validity check?
17127 cfg.cls += " " + this.inputType + "-" + this.weight;
17130 if (this.disabled) {
17131 input.disabled=true;
17135 input.checked = this.checked;
17139 input.name = this.name;
17143 input.cls += ' input-' + this.size;
17148 ['xs','sm','md','lg'].map(function(size){
17149 if (settings[size]) {
17150 cfg.cls += ' col-' + size + '-' + settings[size];
17154 var inputblock = input;
17156 if (this.before || this.after) {
17159 cls : 'input-group',
17164 inputblock.cn.push({
17166 cls : 'input-group-addon',
17171 inputblock.cn.push(input);
17174 inputblock.cn.push({
17176 cls : 'input-group-addon',
17183 if (align ==='left' && this.fieldLabel.length) {
17184 Roo.log("left and has label");
17190 cls : 'control-label col-md-' + this.labelWidth,
17191 html : this.fieldLabel
17195 cls : "col-md-" + (12 - this.labelWidth),
17202 } else if ( this.fieldLabel.length) {
17207 tag: this.boxLabel ? 'span' : 'label',
17209 cls: 'control-label box-input-label',
17210 //cls : 'input-group-addon',
17211 html : this.fieldLabel
17221 Roo.log(" no label && no align");
17222 cfg.cn = [ inputblock ] ;
17227 var boxLabelCfg = {
17229 //'for': id, // box label is handled by onclick - so no for...
17231 html: this.boxLabel
17235 boxLabelCfg.tooltip = this.tooltip;
17238 cfg.cn.push(boxLabelCfg);
17248 * return the real input element.
17250 inputEl: function ()
17252 return this.el.select('input.roo-' + this.inputType,true).first();
17255 labelEl: function()
17257 return this.el.select('label.control-label',true).first();
17259 /* depricated... */
17263 return this.labelEl();
17266 initEvents : function()
17268 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17270 this.inputEl().on('click', this.onClick, this);
17272 if (this.boxLabel) {
17273 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17276 this.startValue = this.getValue();
17279 Roo.bootstrap.CheckBox.register(this);
17283 onClick : function()
17285 this.setChecked(!this.checked);
17288 setChecked : function(state,suppressEvent)
17290 this.startValue = this.getValue();
17292 if(this.inputType == 'radio'){
17294 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17295 e.dom.checked = false;
17298 this.inputEl().dom.checked = true;
17300 this.inputEl().dom.value = this.inputValue;
17302 if(suppressEvent !== true){
17303 this.fireEvent('check', this, true);
17311 this.checked = state;
17313 this.inputEl().dom.checked = state;
17315 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17317 if(suppressEvent !== true){
17318 this.fireEvent('check', this, state);
17324 getValue : function()
17326 if(this.inputType == 'radio'){
17327 return this.getGroupValue();
17330 return this.inputEl().getValue();
17334 getGroupValue : function()
17336 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17340 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17343 setValue : function(v,suppressEvent)
17345 if(this.inputType == 'radio'){
17346 this.setGroupValue(v, suppressEvent);
17350 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17355 setGroupValue : function(v, suppressEvent)
17357 this.startValue = this.getValue();
17359 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17360 e.dom.checked = false;
17362 if(e.dom.value == v){
17363 e.dom.checked = true;
17367 if(suppressEvent !== true){
17368 this.fireEvent('check', this, true);
17376 validate : function()
17380 (this.inputType == 'radio' && this.validateRadio()) ||
17381 (this.inputType == 'checkbox' && this.validateCheckbox())
17387 this.markInvalid();
17391 validateRadio : function()
17395 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17396 if(!e.dom.checked){
17408 validateCheckbox : function()
17411 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17414 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17422 for(var i in group){
17427 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17434 * Mark this field as valid
17436 markValid : function()
17438 if(this.allowBlank){
17444 this.fireEvent('valid', this);
17446 if(this.inputType == 'radio'){
17447 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17448 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17449 e.findParent('.form-group', false, true).addClass(_this.validClass);
17456 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17457 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17461 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17467 for(var i in group){
17468 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17469 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17474 * Mark this field as invalid
17475 * @param {String} msg The validation message
17477 markInvalid : function(msg)
17479 if(this.allowBlank){
17485 this.fireEvent('invalid', this, msg);
17487 if(this.inputType == 'radio'){
17488 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17489 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17490 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17497 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17498 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17502 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17508 for(var i in group){
17509 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17510 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17517 Roo.apply(Roo.bootstrap.CheckBox, {
17522 * register a CheckBox Group
17523 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17525 register : function(checkbox)
17527 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17528 this.groups[checkbox.groupId] = {};
17531 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17535 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17539 * fetch a CheckBox Group based on the group ID
17540 * @param {string} the group ID
17541 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17543 get: function(groupId) {
17544 if (typeof(this.groups[groupId]) == 'undefined') {
17548 return this.groups[groupId] ;
17560 *<div class="radio">
17562 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17563 Option one is this and that—be sure to include why it's great
17570 *<label class="radio-inline">fieldLabel</label>
17571 *<label class="radio-inline">
17572 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17580 * @class Roo.bootstrap.Radio
17581 * @extends Roo.bootstrap.CheckBox
17582 * Bootstrap Radio class
17585 * Create a new Radio
17586 * @param {Object} config The config object
17589 Roo.bootstrap.Radio = function(config){
17590 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17594 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17596 inputType: 'radio',
17600 getAutoCreate : function()
17602 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17603 align = align || 'left'; // default...
17610 tag : this.inline ? 'span' : 'div',
17615 var inline = this.inline ? ' radio-inline' : '';
17619 // does not need for, as we wrap the input with it..
17621 cls : 'control-label box-label' + inline,
17624 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17628 //cls : 'control-label' + inline,
17629 html : this.fieldLabel,
17630 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17639 type : this.inputType,
17640 //value : (!this.checked) ? this.valueOff : this.inputValue,
17641 value : this.inputValue,
17643 placeholder : this.placeholder || '' // ?? needed????
17646 if (this.weight) { // Validity check?
17647 input.cls += " radio-" + this.weight;
17649 if (this.disabled) {
17650 input.disabled=true;
17654 input.checked = this.checked;
17658 input.name = this.name;
17662 input.cls += ' input-' + this.size;
17665 //?? can span's inline have a width??
17668 ['xs','sm','md','lg'].map(function(size){
17669 if (settings[size]) {
17670 cfg.cls += ' col-' + size + '-' + settings[size];
17674 var inputblock = input;
17676 if (this.before || this.after) {
17679 cls : 'input-group',
17684 inputblock.cn.push({
17686 cls : 'input-group-addon',
17690 inputblock.cn.push(input);
17692 inputblock.cn.push({
17694 cls : 'input-group-addon',
17702 if (this.fieldLabel && this.fieldLabel.length) {
17703 cfg.cn.push(fieldLabel);
17706 // normal bootstrap puts the input inside the label.
17707 // however with our styled version - it has to go after the input.
17709 //lbl.cn.push(inputblock);
17713 cls: 'radio' + inline,
17720 cfg.cn.push( lblwrap);
17725 html: this.boxLabel
17734 initEvents : function()
17736 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17738 this.inputEl().on('click', this.onClick, this);
17739 if (this.boxLabel) {
17740 Roo.log('find label')
17741 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17746 inputEl: function ()
17748 return this.el.select('input.roo-radio',true).first();
17750 onClick : function()
17753 this.setChecked(true);
17756 setChecked : function(state,suppressEvent)
17759 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17760 v.dom.checked = false;
17763 Roo.log(this.inputEl().dom);
17764 this.checked = state;
17765 this.inputEl().dom.checked = state;
17767 if(suppressEvent !== true){
17768 this.fireEvent('check', this, state);
17771 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17775 getGroupValue : function()
17778 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17779 if(v.dom.checked == true){
17780 value = v.dom.value;
17788 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17789 * @return {Mixed} value The field value
17791 getValue : function(){
17792 return this.getGroupValue();
17798 //<script type="text/javascript">
17801 * Based Ext JS Library 1.1.1
17802 * Copyright(c) 2006-2007, Ext JS, LLC.
17808 * @class Roo.HtmlEditorCore
17809 * @extends Roo.Component
17810 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17812 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17815 Roo.HtmlEditorCore = function(config){
17818 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17823 * @event initialize
17824 * Fires when the editor is fully initialized (including the iframe)
17825 * @param {Roo.HtmlEditorCore} this
17830 * Fires when the editor is first receives the focus. Any insertion must wait
17831 * until after this event.
17832 * @param {Roo.HtmlEditorCore} this
17836 * @event beforesync
17837 * Fires before the textarea is updated with content from the editor iframe. Return false
17838 * to cancel the sync.
17839 * @param {Roo.HtmlEditorCore} this
17840 * @param {String} html
17844 * @event beforepush
17845 * Fires before the iframe editor is updated with content from the textarea. Return false
17846 * to cancel the push.
17847 * @param {Roo.HtmlEditorCore} this
17848 * @param {String} html
17853 * Fires when the textarea is updated with content from the editor iframe.
17854 * @param {Roo.HtmlEditorCore} this
17855 * @param {String} html
17860 * Fires when the iframe editor is updated with content from the textarea.
17861 * @param {Roo.HtmlEditorCore} this
17862 * @param {String} html
17867 * @event editorevent
17868 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17869 * @param {Roo.HtmlEditorCore} this
17875 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17877 // defaults : white / black...
17878 this.applyBlacklists();
17885 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17889 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17895 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17900 * @cfg {Number} height (in pixels)
17904 * @cfg {Number} width (in pixels)
17909 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17912 stylesheets: false,
17917 // private properties
17918 validationEvent : false,
17920 initialized : false,
17922 sourceEditMode : false,
17923 onFocus : Roo.emptyFn,
17925 hideMode:'offsets',
17929 // blacklist + whitelisted elements..
17936 * Protected method that will not generally be called directly. It
17937 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17938 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17940 getDocMarkup : function(){
17944 // inherit styels from page...??
17945 if (this.stylesheets === false) {
17947 Roo.get(document.head).select('style').each(function(node) {
17948 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17951 Roo.get(document.head).select('link').each(function(node) {
17952 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17955 } else if (!this.stylesheets.length) {
17957 st = '<style type="text/css">' +
17958 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17964 st += '<style type="text/css">' +
17965 'IMG { cursor: pointer } ' +
17969 return '<html><head>' + st +
17970 //<style type="text/css">' +
17971 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17973 ' </head><body class="roo-htmleditor-body"></body></html>';
17977 onRender : function(ct, position)
17980 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17981 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17984 this.el.dom.style.border = '0 none';
17985 this.el.dom.setAttribute('tabIndex', -1);
17986 this.el.addClass('x-hidden hide');
17990 if(Roo.isIE){ // fix IE 1px bogus margin
17991 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17995 this.frameId = Roo.id();
17999 var iframe = this.owner.wrap.createChild({
18001 cls: 'form-control', // bootstrap..
18003 name: this.frameId,
18004 frameBorder : 'no',
18005 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18010 this.iframe = iframe.dom;
18012 this.assignDocWin();
18014 this.doc.designMode = 'on';
18017 this.doc.write(this.getDocMarkup());
18021 var task = { // must defer to wait for browser to be ready
18023 //console.log("run task?" + this.doc.readyState);
18024 this.assignDocWin();
18025 if(this.doc.body || this.doc.readyState == 'complete'){
18027 this.doc.designMode="on";
18031 Roo.TaskMgr.stop(task);
18032 this.initEditor.defer(10, this);
18039 Roo.TaskMgr.start(task);
18044 onResize : function(w, h)
18046 Roo.log('resize: ' +w + ',' + h );
18047 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18051 if(typeof w == 'number'){
18053 this.iframe.style.width = w + 'px';
18055 if(typeof h == 'number'){
18057 this.iframe.style.height = h + 'px';
18059 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18066 * Toggles the editor between standard and source edit mode.
18067 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18069 toggleSourceEdit : function(sourceEditMode){
18071 this.sourceEditMode = sourceEditMode === true;
18073 if(this.sourceEditMode){
18075 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18078 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18079 //this.iframe.className = '';
18082 //this.setSize(this.owner.wrap.getSize());
18083 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18090 * Protected method that will not generally be called directly. If you need/want
18091 * custom HTML cleanup, this is the method you should override.
18092 * @param {String} html The HTML to be cleaned
18093 * return {String} The cleaned HTML
18095 cleanHtml : function(html){
18096 html = String(html);
18097 if(html.length > 5){
18098 if(Roo.isSafari){ // strip safari nonsense
18099 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18102 if(html == ' '){
18109 * HTML Editor -> Textarea
18110 * Protected method that will not generally be called directly. Syncs the contents
18111 * of the editor iframe with the textarea.
18113 syncValue : function(){
18114 if(this.initialized){
18115 var bd = (this.doc.body || this.doc.documentElement);
18116 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18117 var html = bd.innerHTML;
18119 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18120 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18122 html = '<div style="'+m[0]+'">' + html + '</div>';
18125 html = this.cleanHtml(html);
18126 // fix up the special chars.. normaly like back quotes in word...
18127 // however we do not want to do this with chinese..
18128 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18129 var cc = b.charCodeAt();
18131 (cc >= 0x4E00 && cc < 0xA000 ) ||
18132 (cc >= 0x3400 && cc < 0x4E00 ) ||
18133 (cc >= 0xf900 && cc < 0xfb00 )
18139 if(this.owner.fireEvent('beforesync', this, html) !== false){
18140 this.el.dom.value = html;
18141 this.owner.fireEvent('sync', this, html);
18147 * Protected method that will not generally be called directly. Pushes the value of the textarea
18148 * into the iframe editor.
18150 pushValue : function(){
18151 if(this.initialized){
18152 var v = this.el.dom.value.trim();
18154 // if(v.length < 1){
18158 if(this.owner.fireEvent('beforepush', this, v) !== false){
18159 var d = (this.doc.body || this.doc.documentElement);
18161 this.cleanUpPaste();
18162 this.el.dom.value = d.innerHTML;
18163 this.owner.fireEvent('push', this, v);
18169 deferFocus : function(){
18170 this.focus.defer(10, this);
18174 focus : function(){
18175 if(this.win && !this.sourceEditMode){
18182 assignDocWin: function()
18184 var iframe = this.iframe;
18187 this.doc = iframe.contentWindow.document;
18188 this.win = iframe.contentWindow;
18190 // if (!Roo.get(this.frameId)) {
18193 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18194 // this.win = Roo.get(this.frameId).dom.contentWindow;
18196 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18200 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18201 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18206 initEditor : function(){
18207 //console.log("INIT EDITOR");
18208 this.assignDocWin();
18212 this.doc.designMode="on";
18214 this.doc.write(this.getDocMarkup());
18217 var dbody = (this.doc.body || this.doc.documentElement);
18218 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18219 // this copies styles from the containing element into thsi one..
18220 // not sure why we need all of this..
18221 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18223 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18224 //ss['background-attachment'] = 'fixed'; // w3c
18225 dbody.bgProperties = 'fixed'; // ie
18226 //Roo.DomHelper.applyStyles(dbody, ss);
18227 Roo.EventManager.on(this.doc, {
18228 //'mousedown': this.onEditorEvent,
18229 'mouseup': this.onEditorEvent,
18230 'dblclick': this.onEditorEvent,
18231 'click': this.onEditorEvent,
18232 'keyup': this.onEditorEvent,
18237 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18239 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18240 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18242 this.initialized = true;
18244 this.owner.fireEvent('initialize', this);
18249 onDestroy : function(){
18255 //for (var i =0; i < this.toolbars.length;i++) {
18256 // // fixme - ask toolbars for heights?
18257 // this.toolbars[i].onDestroy();
18260 //this.wrap.dom.innerHTML = '';
18261 //this.wrap.remove();
18266 onFirstFocus : function(){
18268 this.assignDocWin();
18271 this.activated = true;
18274 if(Roo.isGecko){ // prevent silly gecko errors
18276 var s = this.win.getSelection();
18277 if(!s.focusNode || s.focusNode.nodeType != 3){
18278 var r = s.getRangeAt(0);
18279 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18284 this.execCmd('useCSS', true);
18285 this.execCmd('styleWithCSS', false);
18288 this.owner.fireEvent('activate', this);
18292 adjustFont: function(btn){
18293 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18294 //if(Roo.isSafari){ // safari
18297 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18298 if(Roo.isSafari){ // safari
18299 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18300 v = (v < 10) ? 10 : v;
18301 v = (v > 48) ? 48 : v;
18302 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18307 v = Math.max(1, v+adjust);
18309 this.execCmd('FontSize', v );
18312 onEditorEvent : function(e){
18313 this.owner.fireEvent('editorevent', this, e);
18314 // this.updateToolbar();
18315 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18318 insertTag : function(tg)
18320 // could be a bit smarter... -> wrap the current selected tRoo..
18321 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18323 range = this.createRange(this.getSelection());
18324 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18325 wrappingNode.appendChild(range.extractContents());
18326 range.insertNode(wrappingNode);
18333 this.execCmd("formatblock", tg);
18337 insertText : function(txt)
18341 var range = this.createRange();
18342 range.deleteContents();
18343 //alert(Sender.getAttribute('label'));
18345 range.insertNode(this.doc.createTextNode(txt));
18351 * Executes a Midas editor command on the editor document and performs necessary focus and
18352 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18353 * @param {String} cmd The Midas command
18354 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18356 relayCmd : function(cmd, value){
18358 this.execCmd(cmd, value);
18359 this.owner.fireEvent('editorevent', this);
18360 //this.updateToolbar();
18361 this.owner.deferFocus();
18365 * Executes a Midas editor command directly on the editor document.
18366 * For visual commands, you should use {@link #relayCmd} instead.
18367 * <b>This should only be called after the editor is initialized.</b>
18368 * @param {String} cmd The Midas command
18369 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18371 execCmd : function(cmd, value){
18372 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18379 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18381 * @param {String} text | dom node..
18383 insertAtCursor : function(text)
18388 if(!this.activated){
18394 var r = this.doc.selection.createRange();
18405 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18409 // from jquery ui (MIT licenced)
18411 var win = this.win;
18413 if (win.getSelection && win.getSelection().getRangeAt) {
18414 range = win.getSelection().getRangeAt(0);
18415 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18416 range.insertNode(node);
18417 } else if (win.document.selection && win.document.selection.createRange) {
18418 // no firefox support
18419 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18420 win.document.selection.createRange().pasteHTML(txt);
18422 // no firefox support
18423 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18424 this.execCmd('InsertHTML', txt);
18433 mozKeyPress : function(e){
18435 var c = e.getCharCode(), cmd;
18438 c = String.fromCharCode(c).toLowerCase();
18452 this.cleanUpPaste.defer(100, this);
18460 e.preventDefault();
18468 fixKeys : function(){ // load time branching for fastest keydown performance
18470 return function(e){
18471 var k = e.getKey(), r;
18474 r = this.doc.selection.createRange();
18477 r.pasteHTML('    ');
18484 r = this.doc.selection.createRange();
18486 var target = r.parentElement();
18487 if(!target || target.tagName.toLowerCase() != 'li'){
18489 r.pasteHTML('<br />');
18495 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18496 this.cleanUpPaste.defer(100, this);
18502 }else if(Roo.isOpera){
18503 return function(e){
18504 var k = e.getKey();
18508 this.execCmd('InsertHTML','    ');
18511 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18512 this.cleanUpPaste.defer(100, this);
18517 }else if(Roo.isSafari){
18518 return function(e){
18519 var k = e.getKey();
18523 this.execCmd('InsertText','\t');
18527 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18528 this.cleanUpPaste.defer(100, this);
18536 getAllAncestors: function()
18538 var p = this.getSelectedNode();
18541 a.push(p); // push blank onto stack..
18542 p = this.getParentElement();
18546 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18550 a.push(this.doc.body);
18554 lastSelNode : false,
18557 getSelection : function()
18559 this.assignDocWin();
18560 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18563 getSelectedNode: function()
18565 // this may only work on Gecko!!!
18567 // should we cache this!!!!
18572 var range = this.createRange(this.getSelection()).cloneRange();
18575 var parent = range.parentElement();
18577 var testRange = range.duplicate();
18578 testRange.moveToElementText(parent);
18579 if (testRange.inRange(range)) {
18582 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18585 parent = parent.parentElement;
18590 // is ancestor a text element.
18591 var ac = range.commonAncestorContainer;
18592 if (ac.nodeType == 3) {
18593 ac = ac.parentNode;
18596 var ar = ac.childNodes;
18599 var other_nodes = [];
18600 var has_other_nodes = false;
18601 for (var i=0;i<ar.length;i++) {
18602 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18605 // fullly contained node.
18607 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18612 // probably selected..
18613 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18614 other_nodes.push(ar[i]);
18618 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18623 has_other_nodes = true;
18625 if (!nodes.length && other_nodes.length) {
18626 nodes= other_nodes;
18628 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18634 createRange: function(sel)
18636 // this has strange effects when using with
18637 // top toolbar - not sure if it's a great idea.
18638 //this.editor.contentWindow.focus();
18639 if (typeof sel != "undefined") {
18641 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18643 return this.doc.createRange();
18646 return this.doc.createRange();
18649 getParentElement: function()
18652 this.assignDocWin();
18653 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18655 var range = this.createRange(sel);
18658 var p = range.commonAncestorContainer;
18659 while (p.nodeType == 3) { // text node
18670 * Range intersection.. the hard stuff...
18674 * [ -- selected range --- ]
18678 * if end is before start or hits it. fail.
18679 * if start is after end or hits it fail.
18681 * if either hits (but other is outside. - then it's not
18687 // @see http://www.thismuchiknow.co.uk/?p=64.
18688 rangeIntersectsNode : function(range, node)
18690 var nodeRange = node.ownerDocument.createRange();
18692 nodeRange.selectNode(node);
18694 nodeRange.selectNodeContents(node);
18697 var rangeStartRange = range.cloneRange();
18698 rangeStartRange.collapse(true);
18700 var rangeEndRange = range.cloneRange();
18701 rangeEndRange.collapse(false);
18703 var nodeStartRange = nodeRange.cloneRange();
18704 nodeStartRange.collapse(true);
18706 var nodeEndRange = nodeRange.cloneRange();
18707 nodeEndRange.collapse(false);
18709 return rangeStartRange.compareBoundaryPoints(
18710 Range.START_TO_START, nodeEndRange) == -1 &&
18711 rangeEndRange.compareBoundaryPoints(
18712 Range.START_TO_START, nodeStartRange) == 1;
18716 rangeCompareNode : function(range, node)
18718 var nodeRange = node.ownerDocument.createRange();
18720 nodeRange.selectNode(node);
18722 nodeRange.selectNodeContents(node);
18726 range.collapse(true);
18728 nodeRange.collapse(true);
18730 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18731 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18733 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18735 var nodeIsBefore = ss == 1;
18736 var nodeIsAfter = ee == -1;
18738 if (nodeIsBefore && nodeIsAfter)
18740 if (!nodeIsBefore && nodeIsAfter)
18741 return 1; //right trailed.
18743 if (nodeIsBefore && !nodeIsAfter)
18744 return 2; // left trailed.
18749 // private? - in a new class?
18750 cleanUpPaste : function()
18752 // cleans up the whole document..
18753 Roo.log('cleanuppaste');
18755 this.cleanUpChildren(this.doc.body);
18756 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18757 if (clean != this.doc.body.innerHTML) {
18758 this.doc.body.innerHTML = clean;
18763 cleanWordChars : function(input) {// change the chars to hex code
18764 var he = Roo.HtmlEditorCore;
18766 var output = input;
18767 Roo.each(he.swapCodes, function(sw) {
18768 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18770 output = output.replace(swapper, sw[1]);
18777 cleanUpChildren : function (n)
18779 if (!n.childNodes.length) {
18782 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18783 this.cleanUpChild(n.childNodes[i]);
18790 cleanUpChild : function (node)
18793 //console.log(node);
18794 if (node.nodeName == "#text") {
18795 // clean up silly Windows -- stuff?
18798 if (node.nodeName == "#comment") {
18799 node.parentNode.removeChild(node);
18800 // clean up silly Windows -- stuff?
18803 var lcname = node.tagName.toLowerCase();
18804 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18805 // whitelist of tags..
18807 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18809 node.parentNode.removeChild(node);
18814 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18816 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18817 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18819 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18820 // remove_keep_children = true;
18823 if (remove_keep_children) {
18824 this.cleanUpChildren(node);
18825 // inserts everything just before this node...
18826 while (node.childNodes.length) {
18827 var cn = node.childNodes[0];
18828 node.removeChild(cn);
18829 node.parentNode.insertBefore(cn, node);
18831 node.parentNode.removeChild(node);
18835 if (!node.attributes || !node.attributes.length) {
18836 this.cleanUpChildren(node);
18840 function cleanAttr(n,v)
18843 if (v.match(/^\./) || v.match(/^\//)) {
18846 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18849 if (v.match(/^#/)) {
18852 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18853 node.removeAttribute(n);
18857 var cwhite = this.cwhite;
18858 var cblack = this.cblack;
18860 function cleanStyle(n,v)
18862 if (v.match(/expression/)) { //XSS?? should we even bother..
18863 node.removeAttribute(n);
18867 var parts = v.split(/;/);
18870 Roo.each(parts, function(p) {
18871 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18875 var l = p.split(':').shift().replace(/\s+/g,'');
18876 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18878 if ( cwhite.length && cblack.indexOf(l) > -1) {
18879 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18880 //node.removeAttribute(n);
18884 // only allow 'c whitelisted system attributes'
18885 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18886 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18887 //node.removeAttribute(n);
18897 if (clean.length) {
18898 node.setAttribute(n, clean.join(';'));
18900 node.removeAttribute(n);
18906 for (var i = node.attributes.length-1; i > -1 ; i--) {
18907 var a = node.attributes[i];
18910 if (a.name.toLowerCase().substr(0,2)=='on') {
18911 node.removeAttribute(a.name);
18914 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18915 node.removeAttribute(a.name);
18918 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18919 cleanAttr(a.name,a.value); // fixme..
18922 if (a.name == 'style') {
18923 cleanStyle(a.name,a.value);
18926 /// clean up MS crap..
18927 // tecnically this should be a list of valid class'es..
18930 if (a.name == 'class') {
18931 if (a.value.match(/^Mso/)) {
18932 node.className = '';
18935 if (a.value.match(/body/)) {
18936 node.className = '';
18947 this.cleanUpChildren(node);
18952 * Clean up MS wordisms...
18954 cleanWord : function(node)
18957 var cleanWordChildren = function()
18959 if (!node.childNodes.length) {
18962 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18963 _t.cleanWord(node.childNodes[i]);
18969 this.cleanWord(this.doc.body);
18972 if (node.nodeName == "#text") {
18973 // clean up silly Windows -- stuff?
18976 if (node.nodeName == "#comment") {
18977 node.parentNode.removeChild(node);
18978 // clean up silly Windows -- stuff?
18982 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18983 node.parentNode.removeChild(node);
18987 // remove - but keep children..
18988 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18989 while (node.childNodes.length) {
18990 var cn = node.childNodes[0];
18991 node.removeChild(cn);
18992 node.parentNode.insertBefore(cn, node);
18994 node.parentNode.removeChild(node);
18995 cleanWordChildren();
18999 if (node.className.length) {
19001 var cn = node.className.split(/\W+/);
19003 Roo.each(cn, function(cls) {
19004 if (cls.match(/Mso[a-zA-Z]+/)) {
19009 node.className = cna.length ? cna.join(' ') : '';
19011 node.removeAttribute("class");
19015 if (node.hasAttribute("lang")) {
19016 node.removeAttribute("lang");
19019 if (node.hasAttribute("style")) {
19021 var styles = node.getAttribute("style").split(";");
19023 Roo.each(styles, function(s) {
19024 if (!s.match(/:/)) {
19027 var kv = s.split(":");
19028 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19031 // what ever is left... we allow.
19034 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19035 if (!nstyle.length) {
19036 node.removeAttribute('style');
19040 cleanWordChildren();
19044 domToHTML : function(currentElement, depth, nopadtext) {
19046 depth = depth || 0;
19047 nopadtext = nopadtext || false;
19049 if (!currentElement) {
19050 return this.domToHTML(this.doc.body);
19053 //Roo.log(currentElement);
19055 var allText = false;
19056 var nodeName = currentElement.nodeName;
19057 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19059 if (nodeName == '#text') {
19061 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19066 if (nodeName != 'BODY') {
19069 // Prints the node tagName, such as <A>, <IMG>, etc
19072 for(i = 0; i < currentElement.attributes.length;i++) {
19074 var aname = currentElement.attributes.item(i).name;
19075 if (!currentElement.attributes.item(i).value.length) {
19078 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19081 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19090 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19093 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19098 // Traverse the tree
19100 var currentElementChild = currentElement.childNodes.item(i);
19101 var allText = true;
19102 var innerHTML = '';
19104 while (currentElementChild) {
19105 // Formatting code (indent the tree so it looks nice on the screen)
19106 var nopad = nopadtext;
19107 if (lastnode == 'SPAN') {
19111 if (currentElementChild.nodeName == '#text') {
19112 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19113 toadd = nopadtext ? toadd : toadd.trim();
19114 if (!nopad && toadd.length > 80) {
19115 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19117 innerHTML += toadd;
19120 currentElementChild = currentElement.childNodes.item(i);
19126 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19128 // Recursively traverse the tree structure of the child node
19129 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19130 lastnode = currentElementChild.nodeName;
19132 currentElementChild=currentElement.childNodes.item(i);
19138 // The remaining code is mostly for formatting the tree
19139 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19144 ret+= "</"+tagName+">";
19150 applyBlacklists : function()
19152 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19153 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19157 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19158 if (b.indexOf(tag) > -1) {
19161 this.white.push(tag);
19165 Roo.each(w, function(tag) {
19166 if (b.indexOf(tag) > -1) {
19169 if (this.white.indexOf(tag) > -1) {
19172 this.white.push(tag);
19177 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19178 if (w.indexOf(tag) > -1) {
19181 this.black.push(tag);
19185 Roo.each(b, function(tag) {
19186 if (w.indexOf(tag) > -1) {
19189 if (this.black.indexOf(tag) > -1) {
19192 this.black.push(tag);
19197 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19198 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19202 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19203 if (b.indexOf(tag) > -1) {
19206 this.cwhite.push(tag);
19210 Roo.each(w, function(tag) {
19211 if (b.indexOf(tag) > -1) {
19214 if (this.cwhite.indexOf(tag) > -1) {
19217 this.cwhite.push(tag);
19222 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19223 if (w.indexOf(tag) > -1) {
19226 this.cblack.push(tag);
19230 Roo.each(b, function(tag) {
19231 if (w.indexOf(tag) > -1) {
19234 if (this.cblack.indexOf(tag) > -1) {
19237 this.cblack.push(tag);
19242 setStylesheets : function(stylesheets)
19244 if(typeof(stylesheets) == 'string'){
19245 Roo.get(this.iframe.contentDocument.head).createChild({
19247 rel : 'stylesheet',
19256 Roo.each(stylesheets, function(s) {
19261 Roo.get(_this.iframe.contentDocument.head).createChild({
19263 rel : 'stylesheet',
19272 removeStylesheets : function()
19276 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19281 // hide stuff that is not compatible
19295 * @event specialkey
19299 * @cfg {String} fieldClass @hide
19302 * @cfg {String} focusClass @hide
19305 * @cfg {String} autoCreate @hide
19308 * @cfg {String} inputType @hide
19311 * @cfg {String} invalidClass @hide
19314 * @cfg {String} invalidText @hide
19317 * @cfg {String} msgFx @hide
19320 * @cfg {String} validateOnBlur @hide
19324 Roo.HtmlEditorCore.white = [
19325 'area', 'br', 'img', 'input', 'hr', 'wbr',
19327 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19328 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19329 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19330 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19331 'table', 'ul', 'xmp',
19333 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19336 'dir', 'menu', 'ol', 'ul', 'dl',
19342 Roo.HtmlEditorCore.black = [
19343 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19345 'base', 'basefont', 'bgsound', 'blink', 'body',
19346 'frame', 'frameset', 'head', 'html', 'ilayer',
19347 'iframe', 'layer', 'link', 'meta', 'object',
19348 'script', 'style' ,'title', 'xml' // clean later..
19350 Roo.HtmlEditorCore.clean = [
19351 'script', 'style', 'title', 'xml'
19353 Roo.HtmlEditorCore.remove = [
19358 Roo.HtmlEditorCore.ablack = [
19362 Roo.HtmlEditorCore.aclean = [
19363 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19367 Roo.HtmlEditorCore.pwhite= [
19368 'http', 'https', 'mailto'
19371 // white listed style attributes.
19372 Roo.HtmlEditorCore.cwhite= [
19373 // 'text-align', /// default is to allow most things..
19379 // black listed style attributes.
19380 Roo.HtmlEditorCore.cblack= [
19381 // 'font-size' -- this can be set by the project
19385 Roo.HtmlEditorCore.swapCodes =[
19404 * @class Roo.bootstrap.HtmlEditor
19405 * @extends Roo.bootstrap.TextArea
19406 * Bootstrap HtmlEditor class
19409 * Create a new HtmlEditor
19410 * @param {Object} config The config object
19413 Roo.bootstrap.HtmlEditor = function(config){
19414 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19415 if (!this.toolbars) {
19416 this.toolbars = [];
19418 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19421 * @event initialize
19422 * Fires when the editor is fully initialized (including the iframe)
19423 * @param {HtmlEditor} this
19428 * Fires when the editor is first receives the focus. Any insertion must wait
19429 * until after this event.
19430 * @param {HtmlEditor} this
19434 * @event beforesync
19435 * Fires before the textarea is updated with content from the editor iframe. Return false
19436 * to cancel the sync.
19437 * @param {HtmlEditor} this
19438 * @param {String} html
19442 * @event beforepush
19443 * Fires before the iframe editor is updated with content from the textarea. Return false
19444 * to cancel the push.
19445 * @param {HtmlEditor} this
19446 * @param {String} html
19451 * Fires when the textarea is updated with content from the editor iframe.
19452 * @param {HtmlEditor} this
19453 * @param {String} html
19458 * Fires when the iframe editor is updated with content from the textarea.
19459 * @param {HtmlEditor} this
19460 * @param {String} html
19464 * @event editmodechange
19465 * Fires when the editor switches edit modes
19466 * @param {HtmlEditor} this
19467 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19469 editmodechange: true,
19471 * @event editorevent
19472 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19473 * @param {HtmlEditor} this
19477 * @event firstfocus
19478 * Fires when on first focus - needed by toolbars..
19479 * @param {HtmlEditor} this
19484 * Auto save the htmlEditor value as a file into Events
19485 * @param {HtmlEditor} this
19489 * @event savedpreview
19490 * preview the saved version of htmlEditor
19491 * @param {HtmlEditor} this
19498 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19502 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19507 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19512 * @cfg {Number} height (in pixels)
19516 * @cfg {Number} width (in pixels)
19521 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19524 stylesheets: false,
19529 // private properties
19530 validationEvent : false,
19532 initialized : false,
19535 onFocus : Roo.emptyFn,
19537 hideMode:'offsets',
19540 tbContainer : false,
19542 toolbarContainer :function() {
19543 return this.wrap.select('.x-html-editor-tb',true).first();
19547 * Protected method that will not generally be called directly. It
19548 * is called when the editor creates its toolbar. Override this method if you need to
19549 * add custom toolbar buttons.
19550 * @param {HtmlEditor} editor
19552 createToolbar : function(){
19554 Roo.log("create toolbars");
19556 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19557 this.toolbars[0].render(this.toolbarContainer());
19561 // if (!editor.toolbars || !editor.toolbars.length) {
19562 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19565 // for (var i =0 ; i < editor.toolbars.length;i++) {
19566 // editor.toolbars[i] = Roo.factory(
19567 // typeof(editor.toolbars[i]) == 'string' ?
19568 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19569 // Roo.bootstrap.HtmlEditor);
19570 // editor.toolbars[i].init(editor);
19576 onRender : function(ct, position)
19578 // Roo.log("Call onRender: " + this.xtype);
19580 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19582 this.wrap = this.inputEl().wrap({
19583 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19586 this.editorcore.onRender(ct, position);
19588 if (this.resizable) {
19589 this.resizeEl = new Roo.Resizable(this.wrap, {
19593 minHeight : this.height,
19594 height: this.height,
19595 handles : this.resizable,
19598 resize : function(r, w, h) {
19599 _t.onResize(w,h); // -something
19605 this.createToolbar(this);
19608 if(!this.width && this.resizable){
19609 this.setSize(this.wrap.getSize());
19611 if (this.resizeEl) {
19612 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19613 // should trigger onReize..
19619 onResize : function(w, h)
19621 Roo.log('resize: ' +w + ',' + h );
19622 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19626 if(this.inputEl() ){
19627 if(typeof w == 'number'){
19628 var aw = w - this.wrap.getFrameWidth('lr');
19629 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19632 if(typeof h == 'number'){
19633 var tbh = -11; // fixme it needs to tool bar size!
19634 for (var i =0; i < this.toolbars.length;i++) {
19635 // fixme - ask toolbars for heights?
19636 tbh += this.toolbars[i].el.getHeight();
19637 //if (this.toolbars[i].footer) {
19638 // tbh += this.toolbars[i].footer.el.getHeight();
19646 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19647 ah -= 5; // knock a few pixes off for look..
19648 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19652 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19653 this.editorcore.onResize(ew,eh);
19658 * Toggles the editor between standard and source edit mode.
19659 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19661 toggleSourceEdit : function(sourceEditMode)
19663 this.editorcore.toggleSourceEdit(sourceEditMode);
19665 if(this.editorcore.sourceEditMode){
19666 Roo.log('editor - showing textarea');
19669 // Roo.log(this.syncValue());
19671 this.inputEl().removeClass(['hide', 'x-hidden']);
19672 this.inputEl().dom.removeAttribute('tabIndex');
19673 this.inputEl().focus();
19675 Roo.log('editor - hiding textarea');
19677 // Roo.log(this.pushValue());
19680 this.inputEl().addClass(['hide', 'x-hidden']);
19681 this.inputEl().dom.setAttribute('tabIndex', -1);
19682 //this.deferFocus();
19685 if(this.resizable){
19686 this.setSize(this.wrap.getSize());
19689 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19692 // private (for BoxComponent)
19693 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19695 // private (for BoxComponent)
19696 getResizeEl : function(){
19700 // private (for BoxComponent)
19701 getPositionEl : function(){
19706 initEvents : function(){
19707 this.originalValue = this.getValue();
19711 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19714 // markInvalid : Roo.emptyFn,
19716 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19719 // clearInvalid : Roo.emptyFn,
19721 setValue : function(v){
19722 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19723 this.editorcore.pushValue();
19728 deferFocus : function(){
19729 this.focus.defer(10, this);
19733 focus : function(){
19734 this.editorcore.focus();
19740 onDestroy : function(){
19746 for (var i =0; i < this.toolbars.length;i++) {
19747 // fixme - ask toolbars for heights?
19748 this.toolbars[i].onDestroy();
19751 this.wrap.dom.innerHTML = '';
19752 this.wrap.remove();
19757 onFirstFocus : function(){
19758 //Roo.log("onFirstFocus");
19759 this.editorcore.onFirstFocus();
19760 for (var i =0; i < this.toolbars.length;i++) {
19761 this.toolbars[i].onFirstFocus();
19767 syncValue : function()
19769 this.editorcore.syncValue();
19772 pushValue : function()
19774 this.editorcore.pushValue();
19778 // hide stuff that is not compatible
19792 * @event specialkey
19796 * @cfg {String} fieldClass @hide
19799 * @cfg {String} focusClass @hide
19802 * @cfg {String} autoCreate @hide
19805 * @cfg {String} inputType @hide
19808 * @cfg {String} invalidClass @hide
19811 * @cfg {String} invalidText @hide
19814 * @cfg {String} msgFx @hide
19817 * @cfg {String} validateOnBlur @hide
19826 Roo.namespace('Roo.bootstrap.htmleditor');
19828 * @class Roo.bootstrap.HtmlEditorToolbar1
19833 new Roo.bootstrap.HtmlEditor({
19836 new Roo.bootstrap.HtmlEditorToolbar1({
19837 disable : { fonts: 1 , format: 1, ..., ... , ...],
19843 * @cfg {Object} disable List of elements to disable..
19844 * @cfg {Array} btns List of additional buttons.
19848 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19851 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19854 Roo.apply(this, config);
19856 // default disabled, based on 'good practice'..
19857 this.disable = this.disable || {};
19858 Roo.applyIf(this.disable, {
19861 specialElements : true
19863 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19865 this.editor = config.editor;
19866 this.editorcore = config.editor.editorcore;
19868 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19870 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19871 // dont call parent... till later.
19873 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19878 editorcore : false,
19883 "h1","h2","h3","h4","h5","h6",
19885 "abbr", "acronym", "address", "cite", "samp", "var",
19889 onRender : function(ct, position)
19891 // Roo.log("Call onRender: " + this.xtype);
19893 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19895 this.el.dom.style.marginBottom = '0';
19897 var editorcore = this.editorcore;
19898 var editor= this.editor;
19901 var btn = function(id,cmd , toggle, handler){
19903 var event = toggle ? 'toggle' : 'click';
19908 xns: Roo.bootstrap,
19911 enableToggle:toggle !== false,
19913 pressed : toggle ? false : null,
19916 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19917 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19926 xns: Roo.bootstrap,
19927 glyphicon : 'font',
19931 xns: Roo.bootstrap,
19935 Roo.each(this.formats, function(f) {
19936 style.menu.items.push({
19938 xns: Roo.bootstrap,
19939 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19944 editorcore.insertTag(this.tagname);
19951 children.push(style);
19954 btn('bold',false,true);
19955 btn('italic',false,true);
19956 btn('align-left', 'justifyleft',true);
19957 btn('align-center', 'justifycenter',true);
19958 btn('align-right' , 'justifyright',true);
19959 btn('link', false, false, function(btn) {
19960 //Roo.log("create link?");
19961 var url = prompt(this.createLinkText, this.defaultLinkValue);
19962 if(url && url != 'http:/'+'/'){
19963 this.editorcore.relayCmd('createlink', url);
19966 btn('list','insertunorderedlist',true);
19967 btn('pencil', false,true, function(btn){
19970 this.toggleSourceEdit(btn.pressed);
19976 xns: Roo.bootstrap,
19981 xns: Roo.bootstrap,
19986 cog.menu.items.push({
19988 xns: Roo.bootstrap,
19989 html : Clean styles,
19994 editorcore.insertTag(this.tagname);
20003 this.xtype = 'NavSimplebar';
20005 for(var i=0;i< children.length;i++) {
20007 this.buttons.add(this.addxtypeChild(children[i]));
20011 editor.on('editorevent', this.updateToolbar, this);
20013 onBtnClick : function(id)
20015 this.editorcore.relayCmd(id);
20016 this.editorcore.focus();
20020 * Protected method that will not generally be called directly. It triggers
20021 * a toolbar update by reading the markup state of the current selection in the editor.
20023 updateToolbar: function(){
20025 if(!this.editorcore.activated){
20026 this.editor.onFirstFocus(); // is this neeed?
20030 var btns = this.buttons;
20031 var doc = this.editorcore.doc;
20032 btns.get('bold').setActive(doc.queryCommandState('bold'));
20033 btns.get('italic').setActive(doc.queryCommandState('italic'));
20034 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20036 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20037 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20038 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20040 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20041 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20044 var ans = this.editorcore.getAllAncestors();
20045 if (this.formatCombo) {
20048 var store = this.formatCombo.store;
20049 this.formatCombo.setValue("");
20050 for (var i =0; i < ans.length;i++) {
20051 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20053 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20061 // hides menus... - so this cant be on a menu...
20062 Roo.bootstrap.MenuMgr.hideAll();
20064 Roo.bootstrap.MenuMgr.hideAll();
20065 //this.editorsyncValue();
20067 onFirstFocus: function() {
20068 this.buttons.each(function(item){
20072 toggleSourceEdit : function(sourceEditMode){
20075 if(sourceEditMode){
20076 Roo.log("disabling buttons");
20077 this.buttons.each( function(item){
20078 if(item.cmd != 'pencil'){
20084 Roo.log("enabling buttons");
20085 if(this.editorcore.initialized){
20086 this.buttons.each( function(item){
20092 Roo.log("calling toggole on editor");
20093 // tell the editor that it's been pressed..
20094 this.editor.toggleSourceEdit(sourceEditMode);
20104 * @class Roo.bootstrap.Table.AbstractSelectionModel
20105 * @extends Roo.util.Observable
20106 * Abstract base class for grid SelectionModels. It provides the interface that should be
20107 * implemented by descendant classes. This class should not be directly instantiated.
20110 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20111 this.locked = false;
20112 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20116 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20117 /** @ignore Called by the grid automatically. Do not call directly. */
20118 init : function(grid){
20124 * Locks the selections.
20127 this.locked = true;
20131 * Unlocks the selections.
20133 unlock : function(){
20134 this.locked = false;
20138 * Returns true if the selections are locked.
20139 * @return {Boolean}
20141 isLocked : function(){
20142 return this.locked;
20146 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20147 * @class Roo.bootstrap.Table.RowSelectionModel
20148 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20149 * It supports multiple selections and keyboard selection/navigation.
20151 * @param {Object} config
20154 Roo.bootstrap.Table.RowSelectionModel = function(config){
20155 Roo.apply(this, config);
20156 this.selections = new Roo.util.MixedCollection(false, function(o){
20161 this.lastActive = false;
20165 * @event selectionchange
20166 * Fires when the selection changes
20167 * @param {SelectionModel} this
20169 "selectionchange" : true,
20171 * @event afterselectionchange
20172 * Fires after the selection changes (eg. by key press or clicking)
20173 * @param {SelectionModel} this
20175 "afterselectionchange" : true,
20177 * @event beforerowselect
20178 * Fires when a row is selected being selected, return false to cancel.
20179 * @param {SelectionModel} this
20180 * @param {Number} rowIndex The selected index
20181 * @param {Boolean} keepExisting False if other selections will be cleared
20183 "beforerowselect" : true,
20186 * Fires when a row is selected.
20187 * @param {SelectionModel} this
20188 * @param {Number} rowIndex The selected index
20189 * @param {Roo.data.Record} r The record
20191 "rowselect" : true,
20193 * @event rowdeselect
20194 * Fires when a row is deselected.
20195 * @param {SelectionModel} this
20196 * @param {Number} rowIndex The selected index
20198 "rowdeselect" : true
20200 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20201 this.locked = false;
20204 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20206 * @cfg {Boolean} singleSelect
20207 * True to allow selection of only one row at a time (defaults to false)
20209 singleSelect : false,
20212 initEvents : function(){
20214 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20215 this.grid.on("mousedown", this.handleMouseDown, this);
20216 }else{ // allow click to work like normal
20217 this.grid.on("rowclick", this.handleDragableRowClick, this);
20220 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20221 "up" : function(e){
20223 this.selectPrevious(e.shiftKey);
20224 }else if(this.last !== false && this.lastActive !== false){
20225 var last = this.last;
20226 this.selectRange(this.last, this.lastActive-1);
20227 this.grid.getView().focusRow(this.lastActive);
20228 if(last !== false){
20232 this.selectFirstRow();
20234 this.fireEvent("afterselectionchange", this);
20236 "down" : function(e){
20238 this.selectNext(e.shiftKey);
20239 }else if(this.last !== false && this.lastActive !== false){
20240 var last = this.last;
20241 this.selectRange(this.last, this.lastActive+1);
20242 this.grid.getView().focusRow(this.lastActive);
20243 if(last !== false){
20247 this.selectFirstRow();
20249 this.fireEvent("afterselectionchange", this);
20254 var view = this.grid.view;
20255 view.on("refresh", this.onRefresh, this);
20256 view.on("rowupdated", this.onRowUpdated, this);
20257 view.on("rowremoved", this.onRemove, this);
20261 onRefresh : function(){
20262 var ds = this.grid.dataSource, i, v = this.grid.view;
20263 var s = this.selections;
20264 s.each(function(r){
20265 if((i = ds.indexOfId(r.id)) != -1){
20274 onRemove : function(v, index, r){
20275 this.selections.remove(r);
20279 onRowUpdated : function(v, index, r){
20280 if(this.isSelected(r)){
20281 v.onRowSelect(index);
20287 * @param {Array} records The records to select
20288 * @param {Boolean} keepExisting (optional) True to keep existing selections
20290 selectRecords : function(records, keepExisting){
20292 this.clearSelections();
20294 var ds = this.grid.dataSource;
20295 for(var i = 0, len = records.length; i < len; i++){
20296 this.selectRow(ds.indexOf(records[i]), true);
20301 * Gets the number of selected rows.
20304 getCount : function(){
20305 return this.selections.length;
20309 * Selects the first row in the grid.
20311 selectFirstRow : function(){
20316 * Select the last row.
20317 * @param {Boolean} keepExisting (optional) True to keep existing selections
20319 selectLastRow : function(keepExisting){
20320 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20324 * Selects the row immediately following the last selected row.
20325 * @param {Boolean} keepExisting (optional) True to keep existing selections
20327 selectNext : function(keepExisting){
20328 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20329 this.selectRow(this.last+1, keepExisting);
20330 this.grid.getView().focusRow(this.last);
20335 * Selects the row that precedes the last selected row.
20336 * @param {Boolean} keepExisting (optional) True to keep existing selections
20338 selectPrevious : function(keepExisting){
20340 this.selectRow(this.last-1, keepExisting);
20341 this.grid.getView().focusRow(this.last);
20346 * Returns the selected records
20347 * @return {Array} Array of selected records
20349 getSelections : function(){
20350 return [].concat(this.selections.items);
20354 * Returns the first selected record.
20357 getSelected : function(){
20358 return this.selections.itemAt(0);
20363 * Clears all selections.
20365 clearSelections : function(fast){
20366 if(this.locked) return;
20368 var ds = this.grid.dataSource;
20369 var s = this.selections;
20370 s.each(function(r){
20371 this.deselectRow(ds.indexOfId(r.id));
20375 this.selections.clear();
20382 * Selects all rows.
20384 selectAll : function(){
20385 if(this.locked) return;
20386 this.selections.clear();
20387 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20388 this.selectRow(i, true);
20393 * Returns True if there is a selection.
20394 * @return {Boolean}
20396 hasSelection : function(){
20397 return this.selections.length > 0;
20401 * Returns True if the specified row is selected.
20402 * @param {Number/Record} record The record or index of the record to check
20403 * @return {Boolean}
20405 isSelected : function(index){
20406 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20407 return (r && this.selections.key(r.id) ? true : false);
20411 * Returns True if the specified record id is selected.
20412 * @param {String} id The id of record to check
20413 * @return {Boolean}
20415 isIdSelected : function(id){
20416 return (this.selections.key(id) ? true : false);
20420 handleMouseDown : function(e, t){
20421 var view = this.grid.getView(), rowIndex;
20422 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20425 if(e.shiftKey && this.last !== false){
20426 var last = this.last;
20427 this.selectRange(last, rowIndex, e.ctrlKey);
20428 this.last = last; // reset the last
20429 view.focusRow(rowIndex);
20431 var isSelected = this.isSelected(rowIndex);
20432 if(e.button !== 0 && isSelected){
20433 view.focusRow(rowIndex);
20434 }else if(e.ctrlKey && isSelected){
20435 this.deselectRow(rowIndex);
20436 }else if(!isSelected){
20437 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20438 view.focusRow(rowIndex);
20441 this.fireEvent("afterselectionchange", this);
20444 handleDragableRowClick : function(grid, rowIndex, e)
20446 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20447 this.selectRow(rowIndex, false);
20448 grid.view.focusRow(rowIndex);
20449 this.fireEvent("afterselectionchange", this);
20454 * Selects multiple rows.
20455 * @param {Array} rows Array of the indexes of the row to select
20456 * @param {Boolean} keepExisting (optional) True to keep existing selections
20458 selectRows : function(rows, keepExisting){
20460 this.clearSelections();
20462 for(var i = 0, len = rows.length; i < len; i++){
20463 this.selectRow(rows[i], true);
20468 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20469 * @param {Number} startRow The index of the first row in the range
20470 * @param {Number} endRow The index of the last row in the range
20471 * @param {Boolean} keepExisting (optional) True to retain existing selections
20473 selectRange : function(startRow, endRow, keepExisting){
20474 if(this.locked) return;
20476 this.clearSelections();
20478 if(startRow <= endRow){
20479 for(var i = startRow; i <= endRow; i++){
20480 this.selectRow(i, true);
20483 for(var i = startRow; i >= endRow; i--){
20484 this.selectRow(i, true);
20490 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20491 * @param {Number} startRow The index of the first row in the range
20492 * @param {Number} endRow The index of the last row in the range
20494 deselectRange : function(startRow, endRow, preventViewNotify){
20495 if(this.locked) return;
20496 for(var i = startRow; i <= endRow; i++){
20497 this.deselectRow(i, preventViewNotify);
20503 * @param {Number} row The index of the row to select
20504 * @param {Boolean} keepExisting (optional) True to keep existing selections
20506 selectRow : function(index, keepExisting, preventViewNotify){
20507 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20508 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20509 if(!keepExisting || this.singleSelect){
20510 this.clearSelections();
20512 var r = this.grid.dataSource.getAt(index);
20513 this.selections.add(r);
20514 this.last = this.lastActive = index;
20515 if(!preventViewNotify){
20516 this.grid.getView().onRowSelect(index);
20518 this.fireEvent("rowselect", this, index, r);
20519 this.fireEvent("selectionchange", this);
20525 * @param {Number} row The index of the row to deselect
20527 deselectRow : function(index, preventViewNotify){
20528 if(this.locked) return;
20529 if(this.last == index){
20532 if(this.lastActive == index){
20533 this.lastActive = false;
20535 var r = this.grid.dataSource.getAt(index);
20536 this.selections.remove(r);
20537 if(!preventViewNotify){
20538 this.grid.getView().onRowDeselect(index);
20540 this.fireEvent("rowdeselect", this, index);
20541 this.fireEvent("selectionchange", this);
20545 restoreLast : function(){
20547 this.last = this._last;
20552 acceptsNav : function(row, col, cm){
20553 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20557 onEditorKey : function(field, e){
20558 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20563 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20565 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20567 }else if(k == e.ENTER && !e.ctrlKey){
20571 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20573 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20575 }else if(k == e.ESC){
20579 g.startEditing(newCell[0], newCell[1]);
20584 * Ext JS Library 1.1.1
20585 * Copyright(c) 2006-2007, Ext JS, LLC.
20587 * Originally Released Under LGPL - original licence link has changed is not relivant.
20590 * <script type="text/javascript">
20594 * @class Roo.bootstrap.PagingToolbar
20596 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20598 * Create a new PagingToolbar
20599 * @param {Object} config The config object
20601 Roo.bootstrap.PagingToolbar = function(config)
20603 // old args format still supported... - xtype is prefered..
20604 // created from xtype...
20605 var ds = config.dataSource;
20606 this.toolbarItems = [];
20607 if (config.items) {
20608 this.toolbarItems = config.items;
20609 // config.items = [];
20612 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20619 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20623 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20625 * @cfg {Roo.data.Store} dataSource
20626 * The underlying data store providing the paged data
20629 * @cfg {String/HTMLElement/Element} container
20630 * container The id or element that will contain the toolbar
20633 * @cfg {Boolean} displayInfo
20634 * True to display the displayMsg (defaults to false)
20637 * @cfg {Number} pageSize
20638 * The number of records to display per page (defaults to 20)
20642 * @cfg {String} displayMsg
20643 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20645 displayMsg : 'Displaying {0} - {1} of {2}',
20647 * @cfg {String} emptyMsg
20648 * The message to display when no records are found (defaults to "No data to display")
20650 emptyMsg : 'No data to display',
20652 * Customizable piece of the default paging text (defaults to "Page")
20655 beforePageText : "Page",
20657 * Customizable piece of the default paging text (defaults to "of %0")
20660 afterPageText : "of {0}",
20662 * Customizable piece of the default paging text (defaults to "First Page")
20665 firstText : "First Page",
20667 * Customizable piece of the default paging text (defaults to "Previous Page")
20670 prevText : "Previous Page",
20672 * Customizable piece of the default paging text (defaults to "Next Page")
20675 nextText : "Next Page",
20677 * Customizable piece of the default paging text (defaults to "Last Page")
20680 lastText : "Last Page",
20682 * Customizable piece of the default paging text (defaults to "Refresh")
20685 refreshText : "Refresh",
20689 onRender : function(ct, position)
20691 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20692 this.navgroup.parentId = this.id;
20693 this.navgroup.onRender(this.el, null);
20694 // add the buttons to the navgroup
20696 if(this.displayInfo){
20697 Roo.log(this.el.select('ul.navbar-nav',true).first());
20698 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20699 this.displayEl = this.el.select('.x-paging-info', true).first();
20700 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20701 // this.displayEl = navel.el.select('span',true).first();
20707 Roo.each(_this.buttons, function(e){
20708 Roo.factory(e).onRender(_this.el, null);
20712 Roo.each(_this.toolbarItems, function(e) {
20713 _this.navgroup.addItem(e);
20717 this.first = this.navgroup.addItem({
20718 tooltip: this.firstText,
20720 icon : 'fa fa-backward',
20722 preventDefault: true,
20723 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20726 this.prev = this.navgroup.addItem({
20727 tooltip: this.prevText,
20729 icon : 'fa fa-step-backward',
20731 preventDefault: true,
20732 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20734 //this.addSeparator();
20737 var field = this.navgroup.addItem( {
20739 cls : 'x-paging-position',
20741 html : this.beforePageText +
20742 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20743 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20746 this.field = field.el.select('input', true).first();
20747 this.field.on("keydown", this.onPagingKeydown, this);
20748 this.field.on("focus", function(){this.dom.select();});
20751 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20752 //this.field.setHeight(18);
20753 //this.addSeparator();
20754 this.next = this.navgroup.addItem({
20755 tooltip: this.nextText,
20757 html : ' <i class="fa fa-step-forward">',
20759 preventDefault: true,
20760 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20762 this.last = this.navgroup.addItem({
20763 tooltip: this.lastText,
20764 icon : 'fa fa-forward',
20767 preventDefault: true,
20768 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20770 //this.addSeparator();
20771 this.loading = this.navgroup.addItem({
20772 tooltip: this.refreshText,
20773 icon: 'fa fa-refresh',
20774 preventDefault: true,
20775 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20781 updateInfo : function(){
20782 if(this.displayEl){
20783 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20784 var msg = count == 0 ?
20788 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20790 this.displayEl.update(msg);
20795 onLoad : function(ds, r, o){
20796 this.cursor = o.params ? o.params.start : 0;
20797 var d = this.getPageData(),
20801 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20802 this.field.dom.value = ap;
20803 this.first.setDisabled(ap == 1);
20804 this.prev.setDisabled(ap == 1);
20805 this.next.setDisabled(ap == ps);
20806 this.last.setDisabled(ap == ps);
20807 this.loading.enable();
20812 getPageData : function(){
20813 var total = this.ds.getTotalCount();
20816 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20817 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20822 onLoadError : function(){
20823 this.loading.enable();
20827 onPagingKeydown : function(e){
20828 var k = e.getKey();
20829 var d = this.getPageData();
20831 var v = this.field.dom.value, pageNum;
20832 if(!v || isNaN(pageNum = parseInt(v, 10))){
20833 this.field.dom.value = d.activePage;
20836 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20837 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20840 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))
20842 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20843 this.field.dom.value = pageNum;
20844 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20847 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20849 var v = this.field.dom.value, pageNum;
20850 var increment = (e.shiftKey) ? 10 : 1;
20851 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20853 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20854 this.field.dom.value = d.activePage;
20857 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20859 this.field.dom.value = parseInt(v, 10) + increment;
20860 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20861 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20868 beforeLoad : function(){
20870 this.loading.disable();
20875 onClick : function(which){
20884 ds.load({params:{start: 0, limit: this.pageSize}});
20887 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20890 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20893 var total = ds.getTotalCount();
20894 var extra = total % this.pageSize;
20895 var lastStart = extra ? (total - extra) : total-this.pageSize;
20896 ds.load({params:{start: lastStart, limit: this.pageSize}});
20899 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20905 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20906 * @param {Roo.data.Store} store The data store to unbind
20908 unbind : function(ds){
20909 ds.un("beforeload", this.beforeLoad, this);
20910 ds.un("load", this.onLoad, this);
20911 ds.un("loadexception", this.onLoadError, this);
20912 ds.un("remove", this.updateInfo, this);
20913 ds.un("add", this.updateInfo, this);
20914 this.ds = undefined;
20918 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20919 * @param {Roo.data.Store} store The data store to bind
20921 bind : function(ds){
20922 ds.on("beforeload", this.beforeLoad, this);
20923 ds.on("load", this.onLoad, this);
20924 ds.on("loadexception", this.onLoadError, this);
20925 ds.on("remove", this.updateInfo, this);
20926 ds.on("add", this.updateInfo, this);
20937 * @class Roo.bootstrap.MessageBar
20938 * @extends Roo.bootstrap.Component
20939 * Bootstrap MessageBar class
20940 * @cfg {String} html contents of the MessageBar
20941 * @cfg {String} weight (info | success | warning | danger) default info
20942 * @cfg {String} beforeClass insert the bar before the given class
20943 * @cfg {Boolean} closable (true | false) default false
20944 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20947 * Create a new Element
20948 * @param {Object} config The config object
20951 Roo.bootstrap.MessageBar = function(config){
20952 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20955 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20961 beforeClass: 'bootstrap-sticky-wrap',
20963 getAutoCreate : function(){
20967 cls: 'alert alert-dismissable alert-' + this.weight,
20972 html: this.html || ''
20978 cfg.cls += ' alert-messages-fixed';
20992 onRender : function(ct, position)
20994 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20997 var cfg = Roo.apply({}, this.getAutoCreate());
21001 cfg.cls += ' ' + this.cls;
21004 cfg.style = this.style;
21006 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21008 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21011 this.el.select('>button.close').on('click', this.hide, this);
21017 if (!this.rendered) {
21023 this.fireEvent('show', this);
21029 if (!this.rendered) {
21035 this.fireEvent('hide', this);
21038 update : function()
21040 // var e = this.el.dom.firstChild;
21042 // if(this.closable){
21043 // e = e.nextSibling;
21046 // e.data = this.html || '';
21048 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21064 * @class Roo.bootstrap.Graph
21065 * @extends Roo.bootstrap.Component
21066 * Bootstrap Graph class
21070 @cfg {String} graphtype bar | vbar | pie
21071 @cfg {number} g_x coodinator | centre x (pie)
21072 @cfg {number} g_y coodinator | centre y (pie)
21073 @cfg {number} g_r radius (pie)
21074 @cfg {number} g_height height of the chart (respected by all elements in the set)
21075 @cfg {number} g_width width of the chart (respected by all elements in the set)
21076 @cfg {Object} title The title of the chart
21079 -opts (object) options for the chart
21081 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21082 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21084 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.
21085 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21087 o stretch (boolean)
21089 -opts (object) options for the pie
21092 o startAngle (number)
21093 o endAngle (number)
21097 * Create a new Input
21098 * @param {Object} config The config object
21101 Roo.bootstrap.Graph = function(config){
21102 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21108 * The img click event for the img.
21109 * @param {Roo.EventObject} e
21115 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21126 //g_colors: this.colors,
21133 getAutoCreate : function(){
21144 onRender : function(ct,position){
21145 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21146 this.raphael = Raphael(this.el.dom);
21148 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21149 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21150 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21151 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21153 r.text(160, 10, "Single Series Chart").attr(txtattr);
21154 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21155 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21156 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21158 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21159 r.barchart(330, 10, 300, 220, data1);
21160 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21161 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21164 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21165 // r.barchart(30, 30, 560, 250, xdata, {
21166 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21167 // axis : "0 0 1 1",
21168 // axisxlabels : xdata
21169 // //yvalues : cols,
21172 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21174 // this.load(null,xdata,{
21175 // axis : "0 0 1 1",
21176 // axisxlabels : xdata
21181 load : function(graphtype,xdata,opts){
21182 this.raphael.clear();
21184 graphtype = this.graphtype;
21189 var r = this.raphael,
21190 fin = function () {
21191 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21193 fout = function () {
21194 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21196 pfin = function() {
21197 this.sector.stop();
21198 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21201 this.label[0].stop();
21202 this.label[0].attr({ r: 7.5 });
21203 this.label[1].attr({ "font-weight": 800 });
21206 pfout = function() {
21207 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21210 this.label[0].animate({ r: 5 }, 500, "bounce");
21211 this.label[1].attr({ "font-weight": 400 });
21217 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21220 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21223 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21224 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21226 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21233 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21238 setTitle: function(o)
21243 initEvents: function() {
21246 this.el.on('click', this.onClick, this);
21250 onClick : function(e)
21252 Roo.log('img onclick');
21253 this.fireEvent('click', this, e);
21265 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21268 * @class Roo.bootstrap.dash.NumberBox
21269 * @extends Roo.bootstrap.Component
21270 * Bootstrap NumberBox class
21271 * @cfg {String} headline Box headline
21272 * @cfg {String} content Box content
21273 * @cfg {String} icon Box icon
21274 * @cfg {String} footer Footer text
21275 * @cfg {String} fhref Footer href
21278 * Create a new NumberBox
21279 * @param {Object} config The config object
21283 Roo.bootstrap.dash.NumberBox = function(config){
21284 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21288 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21297 getAutoCreate : function(){
21301 cls : 'small-box ',
21309 cls : 'roo-headline',
21310 html : this.headline
21314 cls : 'roo-content',
21315 html : this.content
21329 cls : 'ion ' + this.icon
21338 cls : 'small-box-footer',
21339 href : this.fhref || '#',
21343 cfg.cn.push(footer);
21350 onRender : function(ct,position){
21351 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21358 setHeadline: function (value)
21360 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21363 setFooter: function (value, href)
21365 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21368 this.el.select('a.small-box-footer',true).first().attr('href', href);
21373 setContent: function (value)
21375 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21378 initEvents: function()
21392 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21395 * @class Roo.bootstrap.dash.TabBox
21396 * @extends Roo.bootstrap.Component
21397 * Bootstrap TabBox class
21398 * @cfg {String} title Title of the TabBox
21399 * @cfg {String} icon Icon of the TabBox
21400 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21401 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21404 * Create a new TabBox
21405 * @param {Object} config The config object
21409 Roo.bootstrap.dash.TabBox = function(config){
21410 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21415 * When a pane is added
21416 * @param {Roo.bootstrap.dash.TabPane} pane
21420 * @event activatepane
21421 * When a pane is activated
21422 * @param {Roo.bootstrap.dash.TabPane} pane
21424 "activatepane" : true
21432 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21437 tabScrollable : false,
21439 getChildContainer : function()
21441 return this.el.select('.tab-content', true).first();
21444 getAutoCreate : function(){
21448 cls: 'pull-left header',
21456 cls: 'fa ' + this.icon
21462 cls: 'nav nav-tabs pull-right',
21468 if(this.tabScrollable){
21475 cls: 'nav nav-tabs pull-right',
21486 cls: 'nav-tabs-custom',
21491 cls: 'tab-content no-padding',
21499 initEvents : function()
21501 //Roo.log('add add pane handler');
21502 this.on('addpane', this.onAddPane, this);
21505 * Updates the box title
21506 * @param {String} html to set the title to.
21508 setTitle : function(value)
21510 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21512 onAddPane : function(pane)
21514 this.panes.push(pane);
21515 //Roo.log('addpane');
21517 // tabs are rendere left to right..
21518 if(!this.showtabs){
21522 var ctr = this.el.select('.nav-tabs', true).first();
21525 var existing = ctr.select('.nav-tab',true);
21526 var qty = existing.getCount();;
21529 var tab = ctr.createChild({
21531 cls : 'nav-tab' + (qty ? '' : ' active'),
21539 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21542 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21544 pane.el.addClass('active');
21549 onTabClick : function(ev,un,ob,pane)
21551 //Roo.log('tab - prev default');
21552 ev.preventDefault();
21555 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21556 pane.tab.addClass('active');
21557 //Roo.log(pane.title);
21558 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21559 // technically we should have a deactivate event.. but maybe add later.
21560 // and it should not de-activate the selected tab...
21561 this.fireEvent('activatepane', pane);
21562 pane.el.addClass('active');
21563 pane.fireEvent('activate');
21568 getActivePane : function()
21571 Roo.each(this.panes, function(p) {
21572 if(p.el.hasClass('active')){
21593 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21595 * @class Roo.bootstrap.TabPane
21596 * @extends Roo.bootstrap.Component
21597 * Bootstrap TabPane class
21598 * @cfg {Boolean} active (false | true) Default false
21599 * @cfg {String} title title of panel
21603 * Create a new TabPane
21604 * @param {Object} config The config object
21607 Roo.bootstrap.dash.TabPane = function(config){
21608 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21614 * When a pane is activated
21615 * @param {Roo.bootstrap.dash.TabPane} pane
21622 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21627 // the tabBox that this is attached to.
21630 getAutoCreate : function()
21638 cfg.cls += ' active';
21643 initEvents : function()
21645 //Roo.log('trigger add pane handler');
21646 this.parent().fireEvent('addpane', this)
21650 * Updates the tab title
21651 * @param {String} html to set the title to.
21653 setTitle: function(str)
21659 this.tab.select('a', true).first().dom.innerHTML = str;
21676 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21679 * @class Roo.bootstrap.menu.Menu
21680 * @extends Roo.bootstrap.Component
21681 * Bootstrap Menu class - container for Menu
21682 * @cfg {String} html Text of the menu
21683 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21684 * @cfg {String} icon Font awesome icon
21685 * @cfg {String} pos Menu align to (top | bottom) default bottom
21689 * Create a new Menu
21690 * @param {Object} config The config object
21694 Roo.bootstrap.menu.Menu = function(config){
21695 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21699 * @event beforeshow
21700 * Fires before this menu is displayed
21701 * @param {Roo.bootstrap.menu.Menu} this
21705 * @event beforehide
21706 * Fires before this menu is hidden
21707 * @param {Roo.bootstrap.menu.Menu} this
21712 * Fires after this menu is displayed
21713 * @param {Roo.bootstrap.menu.Menu} this
21718 * Fires after this menu is hidden
21719 * @param {Roo.bootstrap.menu.Menu} this
21724 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21725 * @param {Roo.bootstrap.menu.Menu} this
21726 * @param {Roo.EventObject} e
21733 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21737 weight : 'default',
21742 getChildContainer : function() {
21743 if(this.isSubMenu){
21747 return this.el.select('ul.dropdown-menu', true).first();
21750 getAutoCreate : function()
21755 cls : 'roo-menu-text',
21763 cls : 'fa ' + this.icon
21774 cls : 'dropdown-button btn btn-' + this.weight,
21779 cls : 'dropdown-toggle btn btn-' + this.weight,
21789 cls : 'dropdown-menu'
21795 if(this.pos == 'top'){
21796 cfg.cls += ' dropup';
21799 if(this.isSubMenu){
21802 cls : 'dropdown-menu'
21809 onRender : function(ct, position)
21811 this.isSubMenu = ct.hasClass('dropdown-submenu');
21813 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21816 initEvents : function()
21818 if(this.isSubMenu){
21822 this.hidden = true;
21824 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21825 this.triggerEl.on('click', this.onTriggerPress, this);
21827 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21828 this.buttonEl.on('click', this.onClick, this);
21834 if(this.isSubMenu){
21838 return this.el.select('ul.dropdown-menu', true).first();
21841 onClick : function(e)
21843 this.fireEvent("click", this, e);
21846 onTriggerPress : function(e)
21848 if (this.isVisible()) {
21855 isVisible : function(){
21856 return !this.hidden;
21861 this.fireEvent("beforeshow", this);
21863 this.hidden = false;
21864 this.el.addClass('open');
21866 Roo.get(document).on("mouseup", this.onMouseUp, this);
21868 this.fireEvent("show", this);
21875 this.fireEvent("beforehide", this);
21877 this.hidden = true;
21878 this.el.removeClass('open');
21880 Roo.get(document).un("mouseup", this.onMouseUp);
21882 this.fireEvent("hide", this);
21885 onMouseUp : function()
21899 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21902 * @class Roo.bootstrap.menu.Item
21903 * @extends Roo.bootstrap.Component
21904 * Bootstrap MenuItem class
21905 * @cfg {Boolean} submenu (true | false) default false
21906 * @cfg {String} html text of the item
21907 * @cfg {String} href the link
21908 * @cfg {Boolean} disable (true | false) default false
21909 * @cfg {Boolean} preventDefault (true | false) default true
21910 * @cfg {String} icon Font awesome icon
21911 * @cfg {String} pos Submenu align to (left | right) default right
21915 * Create a new Item
21916 * @param {Object} config The config object
21920 Roo.bootstrap.menu.Item = function(config){
21921 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21925 * Fires when the mouse is hovering over this menu
21926 * @param {Roo.bootstrap.menu.Item} this
21927 * @param {Roo.EventObject} e
21932 * Fires when the mouse exits this menu
21933 * @param {Roo.bootstrap.menu.Item} this
21934 * @param {Roo.EventObject} e
21940 * The raw click event for the entire grid.
21941 * @param {Roo.EventObject} e
21947 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21952 preventDefault: true,
21957 getAutoCreate : function()
21962 cls : 'roo-menu-item-text',
21970 cls : 'fa ' + this.icon
21979 href : this.href || '#',
21986 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21990 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21992 if(this.pos == 'left'){
21993 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22000 initEvents : function()
22002 this.el.on('mouseover', this.onMouseOver, this);
22003 this.el.on('mouseout', this.onMouseOut, this);
22005 this.el.select('a', true).first().on('click', this.onClick, this);
22009 onClick : function(e)
22011 if(this.preventDefault){
22012 e.preventDefault();
22015 this.fireEvent("click", this, e);
22018 onMouseOver : function(e)
22020 if(this.submenu && this.pos == 'left'){
22021 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22024 this.fireEvent("mouseover", this, e);
22027 onMouseOut : function(e)
22029 this.fireEvent("mouseout", this, e);
22041 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22044 * @class Roo.bootstrap.menu.Separator
22045 * @extends Roo.bootstrap.Component
22046 * Bootstrap Separator class
22049 * Create a new Separator
22050 * @param {Object} config The config object
22054 Roo.bootstrap.menu.Separator = function(config){
22055 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22058 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22060 getAutoCreate : function(){
22081 * @class Roo.bootstrap.Tooltip
22082 * Bootstrap Tooltip class
22083 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22084 * to determine which dom element triggers the tooltip.
22086 * It needs to add support for additional attributes like tooltip-position
22089 * Create a new Toolti
22090 * @param {Object} config The config object
22093 Roo.bootstrap.Tooltip = function(config){
22094 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22097 Roo.apply(Roo.bootstrap.Tooltip, {
22099 * @function init initialize tooltip monitoring.
22103 currentTip : false,
22104 currentRegion : false,
22110 Roo.get(document).on('mouseover', this.enter ,this);
22111 Roo.get(document).on('mouseout', this.leave, this);
22114 this.currentTip = new Roo.bootstrap.Tooltip();
22117 enter : function(ev)
22119 var dom = ev.getTarget();
22121 //Roo.log(['enter',dom]);
22122 var el = Roo.fly(dom);
22123 if (this.currentEl) {
22125 //Roo.log(this.currentEl);
22126 //Roo.log(this.currentEl.contains(dom));
22127 if (this.currentEl == el) {
22130 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22138 if (this.currentTip.el) {
22139 this.currentTip.el.hide(); // force hiding...
22144 // you can not look for children, as if el is the body.. then everythign is the child..
22145 if (!el.attr('tooltip')) { //
22146 if (!el.select("[tooltip]").elements.length) {
22149 // is the mouse over this child...?
22150 bindEl = el.select("[tooltip]").first();
22151 var xy = ev.getXY();
22152 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22153 //Roo.log("not in region.");
22156 //Roo.log("child element over..");
22159 this.currentEl = bindEl;
22160 this.currentTip.bind(bindEl);
22161 this.currentRegion = Roo.lib.Region.getRegion(dom);
22162 this.currentTip.enter();
22165 leave : function(ev)
22167 var dom = ev.getTarget();
22168 //Roo.log(['leave',dom]);
22169 if (!this.currentEl) {
22174 if (dom != this.currentEl.dom) {
22177 var xy = ev.getXY();
22178 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22181 // only activate leave if mouse cursor is outside... bounding box..
22186 if (this.currentTip) {
22187 this.currentTip.leave();
22189 //Roo.log('clear currentEl');
22190 this.currentEl = false;
22195 'left' : ['r-l', [-2,0], 'right'],
22196 'right' : ['l-r', [2,0], 'left'],
22197 'bottom' : ['t-b', [0,2], 'top'],
22198 'top' : [ 'b-t', [0,-2], 'bottom']
22204 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22209 delay : null, // can be { show : 300 , hide: 500}
22213 hoverState : null, //???
22215 placement : 'bottom',
22217 getAutoCreate : function(){
22224 cls : 'tooltip-arrow'
22227 cls : 'tooltip-inner'
22234 bind : function(el)
22240 enter : function () {
22242 if (this.timeout != null) {
22243 clearTimeout(this.timeout);
22246 this.hoverState = 'in';
22247 //Roo.log("enter - show");
22248 if (!this.delay || !this.delay.show) {
22253 this.timeout = setTimeout(function () {
22254 if (_t.hoverState == 'in') {
22257 }, this.delay.show);
22261 clearTimeout(this.timeout);
22263 this.hoverState = 'out';
22264 if (!this.delay || !this.delay.hide) {
22270 this.timeout = setTimeout(function () {
22271 //Roo.log("leave - timeout");
22273 if (_t.hoverState == 'out') {
22275 Roo.bootstrap.Tooltip.currentEl = false;
22283 this.render(document.body);
22286 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22288 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22290 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22292 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22294 var placement = typeof this.placement == 'function' ?
22295 this.placement.call(this, this.el, on_el) :
22298 var autoToken = /\s?auto?\s?/i;
22299 var autoPlace = autoToken.test(placement);
22301 placement = placement.replace(autoToken, '') || 'top';
22305 //this.el.setXY([0,0]);
22307 //this.el.dom.style.display='block';
22308 this.el.addClass(placement);
22310 //this.el.appendTo(on_el);
22312 var p = this.getPosition();
22313 var box = this.el.getBox();
22318 var align = Roo.bootstrap.Tooltip.alignment[placement];
22319 this.el.alignTo(this.bindEl, align[0],align[1]);
22320 //var arrow = this.el.select('.arrow',true).first();
22321 //arrow.set(align[2],
22323 this.el.addClass('in fade');
22324 this.hoverState = null;
22326 if (this.el.hasClass('fade')) {
22337 //this.el.setXY([0,0]);
22338 this.el.removeClass('in');
22354 * @class Roo.bootstrap.LocationPicker
22355 * @extends Roo.bootstrap.Component
22356 * Bootstrap LocationPicker class
22357 * @cfg {Number} latitude Position when init default 0
22358 * @cfg {Number} longitude Position when init default 0
22359 * @cfg {Number} zoom default 15
22360 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22361 * @cfg {Boolean} mapTypeControl default false
22362 * @cfg {Boolean} disableDoubleClickZoom default false
22363 * @cfg {Boolean} scrollwheel default true
22364 * @cfg {Boolean} streetViewControl default false
22365 * @cfg {Number} radius default 0
22366 * @cfg {String} locationName
22367 * @cfg {Boolean} draggable default true
22368 * @cfg {Boolean} enableAutocomplete default false
22369 * @cfg {Boolean} enableReverseGeocode default true
22370 * @cfg {String} markerTitle
22373 * Create a new LocationPicker
22374 * @param {Object} config The config object
22378 Roo.bootstrap.LocationPicker = function(config){
22380 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22385 * Fires when the picker initialized.
22386 * @param {Roo.bootstrap.LocationPicker} this
22387 * @param {Google Location} location
22391 * @event positionchanged
22392 * Fires when the picker position changed.
22393 * @param {Roo.bootstrap.LocationPicker} this
22394 * @param {Google Location} location
22396 positionchanged : true,
22399 * Fires when the map resize.
22400 * @param {Roo.bootstrap.LocationPicker} this
22405 * Fires when the map show.
22406 * @param {Roo.bootstrap.LocationPicker} this
22411 * Fires when the map hide.
22412 * @param {Roo.bootstrap.LocationPicker} this
22417 * Fires when click the map.
22418 * @param {Roo.bootstrap.LocationPicker} this
22419 * @param {Map event} e
22423 * @event mapRightClick
22424 * Fires when right click the map.
22425 * @param {Roo.bootstrap.LocationPicker} this
22426 * @param {Map event} e
22428 mapRightClick : true,
22430 * @event markerClick
22431 * Fires when click the marker.
22432 * @param {Roo.bootstrap.LocationPicker} this
22433 * @param {Map event} e
22435 markerClick : true,
22437 * @event markerRightClick
22438 * Fires when right click the marker.
22439 * @param {Roo.bootstrap.LocationPicker} this
22440 * @param {Map event} e
22442 markerRightClick : true,
22444 * @event OverlayViewDraw
22445 * Fires when OverlayView Draw
22446 * @param {Roo.bootstrap.LocationPicker} this
22448 OverlayViewDraw : true,
22450 * @event OverlayViewOnAdd
22451 * Fires when OverlayView Draw
22452 * @param {Roo.bootstrap.LocationPicker} this
22454 OverlayViewOnAdd : true,
22456 * @event OverlayViewOnRemove
22457 * Fires when OverlayView Draw
22458 * @param {Roo.bootstrap.LocationPicker} this
22460 OverlayViewOnRemove : true,
22462 * @event OverlayViewShow
22463 * Fires when OverlayView Draw
22464 * @param {Roo.bootstrap.LocationPicker} this
22465 * @param {Pixel} cpx
22467 OverlayViewShow : true,
22469 * @event OverlayViewHide
22470 * Fires when OverlayView Draw
22471 * @param {Roo.bootstrap.LocationPicker} this
22473 OverlayViewHide : true
22478 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22480 gMapContext: false,
22486 mapTypeControl: false,
22487 disableDoubleClickZoom: false,
22489 streetViewControl: false,
22493 enableAutocomplete: false,
22494 enableReverseGeocode: true,
22497 getAutoCreate: function()
22502 cls: 'roo-location-picker'
22508 initEvents: function(ct, position)
22510 if(!this.el.getWidth() || this.isApplied()){
22514 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22519 initial: function()
22521 if(!this.mapTypeId){
22522 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22525 this.gMapContext = this.GMapContext();
22527 this.initOverlayView();
22529 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22533 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22534 _this.setPosition(_this.gMapContext.marker.position);
22537 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22538 _this.fireEvent('mapClick', this, event);
22542 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22543 _this.fireEvent('mapRightClick', this, event);
22547 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22548 _this.fireEvent('markerClick', this, event);
22552 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22553 _this.fireEvent('markerRightClick', this, event);
22557 this.setPosition(this.gMapContext.location);
22559 this.fireEvent('initial', this, this.gMapContext.location);
22562 initOverlayView: function()
22566 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22570 _this.fireEvent('OverlayViewDraw', _this);
22575 _this.fireEvent('OverlayViewOnAdd', _this);
22578 onRemove: function()
22580 _this.fireEvent('OverlayViewOnRemove', _this);
22583 show: function(cpx)
22585 _this.fireEvent('OverlayViewShow', _this, cpx);
22590 _this.fireEvent('OverlayViewHide', _this);
22596 fromLatLngToContainerPixel: function(event)
22598 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22601 isApplied: function()
22603 return this.getGmapContext() == false ? false : true;
22606 getGmapContext: function()
22608 return this.gMapContext
22611 GMapContext: function()
22613 var position = new google.maps.LatLng(this.latitude, this.longitude);
22615 var _map = new google.maps.Map(this.el.dom, {
22618 mapTypeId: this.mapTypeId,
22619 mapTypeControl: this.mapTypeControl,
22620 disableDoubleClickZoom: this.disableDoubleClickZoom,
22621 scrollwheel: this.scrollwheel,
22622 streetViewControl: this.streetViewControl,
22623 locationName: this.locationName,
22624 draggable: this.draggable,
22625 enableAutocomplete: this.enableAutocomplete,
22626 enableReverseGeocode: this.enableReverseGeocode
22629 var _marker = new google.maps.Marker({
22630 position: position,
22632 title: this.markerTitle,
22633 draggable: this.draggable
22640 location: position,
22641 radius: this.radius,
22642 locationName: this.locationName,
22643 addressComponents: {
22644 formatted_address: null,
22645 addressLine1: null,
22646 addressLine2: null,
22648 streetNumber: null,
22652 stateOrProvince: null
22655 domContainer: this.el.dom,
22656 geodecoder: new google.maps.Geocoder()
22660 drawCircle: function(center, radius, options)
22662 if (this.gMapContext.circle != null) {
22663 this.gMapContext.circle.setMap(null);
22667 options = Roo.apply({}, options, {
22668 strokeColor: "#0000FF",
22669 strokeOpacity: .35,
22671 fillColor: "#0000FF",
22675 options.map = this.gMapContext.map;
22676 options.radius = radius;
22677 options.center = center;
22678 this.gMapContext.circle = new google.maps.Circle(options);
22679 return this.gMapContext.circle;
22685 setPosition: function(location)
22687 this.gMapContext.location = location;
22688 this.gMapContext.marker.setPosition(location);
22689 this.gMapContext.map.panTo(location);
22690 this.drawCircle(location, this.gMapContext.radius, {});
22694 if (this.gMapContext.settings.enableReverseGeocode) {
22695 this.gMapContext.geodecoder.geocode({
22696 latLng: this.gMapContext.location
22697 }, function(results, status) {
22699 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22700 _this.gMapContext.locationName = results[0].formatted_address;
22701 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22703 _this.fireEvent('positionchanged', this, location);
22710 this.fireEvent('positionchanged', this, location);
22715 google.maps.event.trigger(this.gMapContext.map, "resize");
22717 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22719 this.fireEvent('resize', this);
22722 setPositionByLatLng: function(latitude, longitude)
22724 this.setPosition(new google.maps.LatLng(latitude, longitude));
22727 getCurrentPosition: function()
22730 latitude: this.gMapContext.location.lat(),
22731 longitude: this.gMapContext.location.lng()
22735 getAddressName: function()
22737 return this.gMapContext.locationName;
22740 getAddressComponents: function()
22742 return this.gMapContext.addressComponents;
22745 address_component_from_google_geocode: function(address_components)
22749 for (var i = 0; i < address_components.length; i++) {
22750 var component = address_components[i];
22751 if (component.types.indexOf("postal_code") >= 0) {
22752 result.postalCode = component.short_name;
22753 } else if (component.types.indexOf("street_number") >= 0) {
22754 result.streetNumber = component.short_name;
22755 } else if (component.types.indexOf("route") >= 0) {
22756 result.streetName = component.short_name;
22757 } else if (component.types.indexOf("neighborhood") >= 0) {
22758 result.city = component.short_name;
22759 } else if (component.types.indexOf("locality") >= 0) {
22760 result.city = component.short_name;
22761 } else if (component.types.indexOf("sublocality") >= 0) {
22762 result.district = component.short_name;
22763 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22764 result.stateOrProvince = component.short_name;
22765 } else if (component.types.indexOf("country") >= 0) {
22766 result.country = component.short_name;
22770 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22771 result.addressLine2 = "";
22775 setZoomLevel: function(zoom)
22777 this.gMapContext.map.setZoom(zoom);
22790 this.fireEvent('show', this);
22801 this.fireEvent('hide', this);
22806 Roo.apply(Roo.bootstrap.LocationPicker, {
22808 OverlayView : function(map, options)
22810 options = options || {};
22824 * @class Roo.bootstrap.Alert
22825 * @extends Roo.bootstrap.Component
22826 * Bootstrap Alert class
22827 * @cfg {String} title The title of alert
22828 * @cfg {String} html The content of alert
22829 * @cfg {String} weight ( success | info | warning | danger )
22830 * @cfg {String} faicon font-awesomeicon
22833 * Create a new alert
22834 * @param {Object} config The config object
22838 Roo.bootstrap.Alert = function(config){
22839 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22843 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22850 getAutoCreate : function()
22859 cls : 'roo-alert-icon'
22864 cls : 'roo-alert-title',
22869 cls : 'roo-alert-text',
22876 cfg.cn[0].cls += ' fa ' + this.faicon;
22880 cfg.cls += ' alert-' + this.weight;
22886 initEvents: function()
22888 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22891 setTitle : function(str)
22893 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22896 setText : function(str)
22898 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22901 setWeight : function(weight)
22904 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22907 this.weight = weight;
22909 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22912 setIcon : function(icon)
22915 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22920 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);