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());
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;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
232 addxtypeChild : function (tree, cntr)
234 Roo.debug && Roo.log('addxtypeChild:' + cntr);
236 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
240 (typeof(tree['flexy:foreach']) != 'undefined');
244 skip_children = false;
245 // render the element if it's not BODY.
246 if (tree.xtype != 'Body') {
248 cn = Roo.factory(tree);
250 cn.parentType = this.xtype; //??
251 cn.parentId = this.id;
253 var build_from_html = Roo.XComponent.build_from_html;
256 // does the container contain child eleemnts with 'xtype' attributes.
257 // that match this xtype..
258 // note - when we render we create these as well..
259 // so we should check to see if body has xtype set.
260 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
262 var self_cntr_el = Roo.get(this[cntr](false));
263 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
265 Roo.log(Roo.XComponent.build_from_html);
266 Roo.log("got echild:");
269 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
270 // and are not displayed -this causes this to use up the wrong element when matching.
271 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
274 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
275 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
281 //echild.dom.removeAttribute('xtype');
283 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
284 Roo.debug && Roo.log(self_cntr_el);
285 Roo.debug && Roo.log(echild);
286 Roo.debug && Roo.log(cn);
292 // if object has flexy:if - then it may or may not be rendered.
293 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
294 // skip a flexy if element.
295 Roo.debug && Roo.log('skipping render');
296 Roo.debug && Roo.log(tree);
298 Roo.debug && Roo.log('skipping all children');
299 skip_children = true;
304 // actually if flexy:foreach is found, we really want to create
305 // multiple copies here...
307 //Roo.log(this[cntr]());
308 cn.render(this[cntr](true));
310 // then add the element..
318 if (typeof (tree.menu) != 'undefined') {
319 tree.menu.parentType = cn.xtype;
320 tree.menu.triggerEl = cn.el;
321 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
325 if (!tree.items || !tree.items.length) {
329 var items = tree.items;
332 //Roo.log(items.length);
334 if (!skip_children) {
335 for(var i =0;i < items.length;i++) {
336 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
342 this.fireEvent('childrenrendered', this);
358 * @class Roo.bootstrap.Body
359 * @extends Roo.bootstrap.Component
360 * Bootstrap Body class
364 * @param {Object} config The config object
367 Roo.bootstrap.Body = function(config){
368 Roo.bootstrap.Body.superclass.constructor.call(this, config);
369 this.el = Roo.get(document.body);
370 if (this.cls && this.cls.length) {
371 Roo.get(document.body).addClass(this.cls);
375 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
380 onRender : function(ct, position)
382 /* Roo.log("Roo.bootstrap.Body - onRender");
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
404 * @class Roo.bootstrap.ButtonGroup
405 * @extends Roo.bootstrap.Component
406 * Bootstrap ButtonGroup class
407 * @cfg {String} size lg | sm | xs (default empty normal)
408 * @cfg {String} align vertical | justified (default none)
409 * @cfg {String} direction up | down (default down)
410 * @cfg {Boolean} toolbar false | true
411 * @cfg {Boolean} btn true | false
416 * @param {Object} config The config object
419 Roo.bootstrap.ButtonGroup = function(config){
420 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
423 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
431 getAutoCreate : function(){
437 cfg.html = this.html || cfg.html;
448 if (['vertical','justified'].indexOf(this.align)!==-1) {
449 cfg.cls = 'btn-group-' + this.align;
451 if (this.align == 'justified') {
452 console.log(this.items);
456 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
457 cfg.cls += ' btn-group-' + this.size;
460 if (this.direction == 'up') {
461 cfg.cls += ' dropup' ;
477 * @class Roo.bootstrap.Button
478 * @extends Roo.bootstrap.Component
479 * Bootstrap Button class
480 * @cfg {String} html The button content
481 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
482 * @cfg {String} size ( lg | sm | xs)
483 * @cfg {String} tag ( a | input | submit)
484 * @cfg {String} href empty or href
485 * @cfg {Boolean} disabled default false;
486 * @cfg {Boolean} isClose default false;
487 * @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)
488 * @cfg {String} badge text for badge
489 * @cfg {String} theme default
490 * @cfg {Boolean} inverse
491 * @cfg {Boolean} toggle
492 * @cfg {String} ontext text for on toggle state
493 * @cfg {String} offtext text for off toggle state
494 * @cfg {Boolean} defaulton
495 * @cfg {Boolean} preventDefault default true
496 * @cfg {Boolean} removeClass remove the standard class..
497 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
500 * Create a new button
501 * @param {Object} config The config object
505 Roo.bootstrap.Button = function(config){
506 Roo.bootstrap.Button.superclass.constructor.call(this, config);
511 * When a butotn is pressed
512 * @param {Roo.bootstrap.Button} this
513 * @param {Roo.EventObject} e
518 * After the button has been toggles
519 * @param {Roo.EventObject} e
520 * @param {boolean} pressed (also available as button.pressed)
526 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
544 preventDefault: true,
553 getAutoCreate : function(){
561 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
562 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
567 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
569 if (this.toggle == true) {
572 cls: 'slider-frame roo-button',
577 'data-off-text':'OFF',
578 cls: 'slider-button',
584 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585 cfg.cls += ' '+this.weight;
594 cfg["aria-hidden"] = true;
596 cfg.html = "×";
602 if (this.theme==='default') {
603 cfg.cls = 'btn roo-button';
605 //if (this.parentType != 'Navbar') {
606 this.weight = this.weight.length ? this.weight : 'default';
608 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
610 cfg.cls += ' btn-' + this.weight;
612 } else if (this.theme==='glow') {
615 cfg.cls = 'btn-glow roo-button';
617 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
619 cfg.cls += ' ' + this.weight;
625 this.cls += ' inverse';
630 cfg.cls += ' active';
634 cfg.disabled = 'disabled';
638 Roo.log('changing to ul' );
640 this.glyphicon = 'caret';
643 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
645 //gsRoo.log(this.parentType);
646 if (this.parentType === 'Navbar' && !this.parent().bar) {
647 Roo.log('changing to li?');
656 href : this.href || '#'
659 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
660 cfg.cls += ' dropdown';
667 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
669 if (this.glyphicon) {
670 cfg.html = ' ' + cfg.html;
675 cls: 'glyphicon glyphicon-' + this.glyphicon
685 // cfg.cls='btn roo-button';
689 var value = cfg.html;
694 cls: 'glyphicon glyphicon-' + this.glyphicon,
713 cfg.cls += ' dropdown';
714 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
717 if (cfg.tag !== 'a' && this.href !== '') {
718 throw "Tag must be a to set href.";
719 } else if (this.href.length > 0) {
720 cfg.href = this.href;
723 if(this.removeClass){
728 cfg.target = this.target;
733 initEvents: function() {
734 // Roo.log('init events?');
735 // Roo.log(this.el.dom);
738 if (typeof (this.menu) != 'undefined') {
739 this.menu.parentType = this.xtype;
740 this.menu.triggerEl = this.el;
741 this.addxtype(Roo.apply({}, this.menu));
745 if (this.el.hasClass('roo-button')) {
746 this.el.on('click', this.onClick, this);
748 this.el.select('.roo-button').on('click', this.onClick, this);
751 if(this.removeClass){
752 this.el.on('click', this.onClick, this);
755 this.el.enableDisplayMode();
758 onClick : function(e)
765 Roo.log('button on click ');
766 if(this.preventDefault){
769 if (this.pressed === true || this.pressed === false) {
770 this.pressed = !this.pressed;
771 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
772 this.fireEvent('toggle', this, e, this.pressed);
776 this.fireEvent('click', this, e);
780 * Enables this button
784 this.disabled = false;
785 this.el.removeClass('disabled');
789 * Disable this button
793 this.disabled = true;
794 this.el.addClass('disabled');
797 * sets the active state on/off,
798 * @param {Boolean} state (optional) Force a particular state
800 setActive : function(v) {
802 this.el[v ? 'addClass' : 'removeClass']('active');
805 * toggles the current active state
807 toggleActive : function()
809 var active = this.el.hasClass('active');
810 this.setActive(!active);
814 setText : function(str)
816 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
820 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
843 * @class Roo.bootstrap.Column
844 * @extends Roo.bootstrap.Component
845 * Bootstrap Column class
846 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
847 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
848 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
849 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
850 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
851 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
852 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
853 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
856 * @cfg {Boolean} hidden (true|false) hide the element
857 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
858 * @cfg {String} fa (ban|check|...) font awesome icon
859 * @cfg {Number} fasize (1|2|....) font awsome size
861 * @cfg {String} icon (info-sign|check|...) glyphicon name
863 * @cfg {String} html content of column.
866 * Create a new Column
867 * @param {Object} config The config object
870 Roo.bootstrap.Column = function(config){
871 Roo.bootstrap.Column.superclass.constructor.call(this, config);
874 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
892 getAutoCreate : function(){
893 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
901 ['xs','sm','md','lg'].map(function(size){
902 //Roo.log( size + ':' + settings[size]);
904 if (settings[size+'off'] !== false) {
905 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
908 if (settings[size] === false) {
911 Roo.log(settings[size]);
912 if (!settings[size]) { // 0 = hidden
913 cfg.cls += ' hidden-' + size;
916 cfg.cls += ' col-' + size + '-' + settings[size];
921 cfg.cls += ' hidden';
924 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
925 cfg.cls +=' alert alert-' + this.alert;
929 if (this.html.length) {
930 cfg.html = this.html;
934 if (this.fasize > 1) {
935 fasize = ' fa-' + this.fasize + 'x';
937 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
942 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
961 * @class Roo.bootstrap.Container
962 * @extends Roo.bootstrap.Component
963 * Bootstrap Container class
964 * @cfg {Boolean} jumbotron is it a jumbotron element
965 * @cfg {String} html content of element
966 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
967 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
968 * @cfg {String} header content of header (for panel)
969 * @cfg {String} footer content of footer (for panel)
970 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
971 * @cfg {String} tag (header|aside|section) type of HTML tag.
972 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
973 * @cfg {String} fa (ban|check|...) font awesome icon
974 * @cfg {String} icon (info-sign|check|...) glyphicon name
975 * @cfg {Boolean} hidden (true|false) hide the element
979 * Create a new Container
980 * @param {Object} config The config object
983 Roo.bootstrap.Container = function(config){
984 Roo.bootstrap.Container.superclass.constructor.call(this, config);
987 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1001 getChildContainer : function() {
1007 if (this.panel.length) {
1008 return this.el.select('.panel-body',true).first();
1015 getAutoCreate : function(){
1018 tag : this.tag || 'div',
1022 if (this.jumbotron) {
1023 cfg.cls = 'jumbotron';
1028 // - this is applied by the parent..
1030 // cfg.cls = this.cls + '';
1033 if (this.sticky.length) {
1035 var bd = Roo.get(document.body);
1036 if (!bd.hasClass('bootstrap-sticky')) {
1037 bd.addClass('bootstrap-sticky');
1038 Roo.select('html',true).setStyle('height', '100%');
1041 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1045 if (this.well.length) {
1046 switch (this.well) {
1049 cfg.cls +=' well well-' +this.well;
1058 cfg.cls += ' hidden';
1062 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1063 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.panel.length) {
1069 cfg.cls += ' panel panel-' + this.panel;
1071 if (this.header.length) {
1074 cls : 'panel-heading',
1077 cls : 'panel-title',
1090 if (this.footer.length) {
1092 cls : 'panel-footer',
1101 body.html = this.html || cfg.html;
1102 // prefix with the icons..
1104 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1107 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1112 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1113 cfg.cls = 'container';
1119 titleEl : function()
1121 if(!this.el || !this.panel.length || !this.header.length){
1125 return this.el.select('.panel-title',true).first();
1128 setTitle : function(v)
1130 var titleEl = this.titleEl();
1136 titleEl.dom.innerHTML = v;
1139 getTitle : function()
1142 var titleEl = this.titleEl();
1148 return titleEl.dom.innerHTML;
1152 this.el.removeClass('hidden');
1155 if (!this.el.hasClass('hidden')) {
1156 this.el.addClass('hidden');
1172 * @class Roo.bootstrap.Img
1173 * @extends Roo.bootstrap.Component
1174 * Bootstrap Img class
1175 * @cfg {Boolean} imgResponsive false | true
1176 * @cfg {String} border rounded | circle | thumbnail
1177 * @cfg {String} src image source
1178 * @cfg {String} alt image alternative text
1179 * @cfg {String} href a tag href
1180 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1183 * Create a new Input
1184 * @param {Object} config The config object
1187 Roo.bootstrap.Img = function(config){
1188 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1194 * The img click event for the img.
1195 * @param {Roo.EventObject} e
1201 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1203 imgResponsive: true,
1209 getAutoCreate : function(){
1213 cls: (this.imgResponsive) ? 'img-responsive' : '',
1217 cfg.html = this.html || cfg.html;
1219 cfg.src = this.src || cfg.src;
1221 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1222 cfg.cls += ' img-' + this.border;
1239 a.target = this.target;
1245 return (this.href) ? a : cfg;
1248 initEvents: function() {
1251 this.el.on('click', this.onClick, this);
1255 onClick : function(e)
1257 Roo.log('img onclick');
1258 this.fireEvent('click', this, e);
1272 * @class Roo.bootstrap.Link
1273 * @extends Roo.bootstrap.Component
1274 * Bootstrap Link Class
1275 * @cfg {String} alt image alternative text
1276 * @cfg {String} href a tag href
1277 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1278 * @cfg {String} html the content of the link.
1279 * @cfg {String} anchor name for the anchor link
1281 * @cfg {Boolean} preventDefault (true | false) default false
1285 * Create a new Input
1286 * @param {Object} config The config object
1289 Roo.bootstrap.Link = function(config){
1290 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1296 * The img click event for the img.
1297 * @param {Roo.EventObject} e
1303 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1307 preventDefault: false,
1311 getAutoCreate : function()
1317 // anchor's do not require html/href...
1318 if (this.anchor === false) {
1319 cfg.html = this.html || 'html-missing';
1320 cfg.href = this.href || '#';
1322 cfg.name = this.anchor;
1323 if (this.html !== false) {
1324 cfg.html = this.html;
1326 if (this.href !== false) {
1327 cfg.href = this.href;
1331 if(this.alt !== false){
1336 if(this.target !== false) {
1337 cfg.target = this.target;
1343 initEvents: function() {
1345 if(!this.href || this.preventDefault){
1346 this.el.on('click', this.onClick, this);
1350 onClick : function(e)
1352 if(this.preventDefault){
1355 //Roo.log('img onclick');
1356 this.fireEvent('click', this, e);
1369 * @class Roo.bootstrap.Header
1370 * @extends Roo.bootstrap.Component
1371 * Bootstrap Header class
1372 * @cfg {String} html content of header
1373 * @cfg {Number} level (1|2|3|4|5|6) default 1
1376 * Create a new Header
1377 * @param {Object} config The config object
1381 Roo.bootstrap.Header = function(config){
1382 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1385 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1393 getAutoCreate : function(){
1398 tag: 'h' + (1 *this.level),
1399 html: this.html || ''
1411 * Ext JS Library 1.1.1
1412 * Copyright(c) 2006-2007, Ext JS, LLC.
1414 * Originally Released Under LGPL - original licence link has changed is not relivant.
1417 * <script type="text/javascript">
1421 * @class Roo.bootstrap.MenuMgr
1422 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1425 Roo.bootstrap.MenuMgr = function(){
1426 var menus, active, groups = {}, attached = false, lastShow = new Date();
1428 // private - called when first menu is created
1431 active = new Roo.util.MixedCollection();
1432 Roo.get(document).addKeyListener(27, function(){
1433 if(active.length > 0){
1441 if(active && active.length > 0){
1442 var c = active.clone();
1452 if(active.length < 1){
1453 Roo.get(document).un("mouseup", onMouseDown);
1461 var last = active.last();
1462 lastShow = new Date();
1465 Roo.get(document).on("mouseup", onMouseDown);
1470 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1471 m.parentMenu.activeChild = m;
1472 }else if(last && last.isVisible()){
1473 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1478 function onBeforeHide(m){
1480 m.activeChild.hide();
1482 if(m.autoHideTimer){
1483 clearTimeout(m.autoHideTimer);
1484 delete m.autoHideTimer;
1489 function onBeforeShow(m){
1490 var pm = m.parentMenu;
1491 if(!pm && !m.allowOtherMenus){
1493 }else if(pm && pm.activeChild && active != m){
1494 pm.activeChild.hide();
1499 function onMouseDown(e){
1500 Roo.log("on MouseDown");
1501 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1509 function onBeforeCheck(mi, state){
1511 var g = groups[mi.group];
1512 for(var i = 0, l = g.length; i < l; i++){
1514 g[i].setChecked(false);
1523 * Hides all menus that are currently visible
1525 hideAll : function(){
1530 register : function(menu){
1534 menus[menu.id] = menu;
1535 menu.on("beforehide", onBeforeHide);
1536 menu.on("hide", onHide);
1537 menu.on("beforeshow", onBeforeShow);
1538 menu.on("show", onShow);
1540 if(g && menu.events["checkchange"]){
1544 groups[g].push(menu);
1545 menu.on("checkchange", onCheck);
1550 * Returns a {@link Roo.menu.Menu} object
1551 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1552 * be used to generate and return a new Menu instance.
1554 get : function(menu){
1555 if(typeof menu == "string"){ // menu id
1557 }else if(menu.events){ // menu instance
1560 /*else if(typeof menu.length == 'number'){ // array of menu items?
1561 return new Roo.bootstrap.Menu({items:menu});
1562 }else{ // otherwise, must be a config
1563 return new Roo.bootstrap.Menu(menu);
1570 unregister : function(menu){
1571 delete menus[menu.id];
1572 menu.un("beforehide", onBeforeHide);
1573 menu.un("hide", onHide);
1574 menu.un("beforeshow", onBeforeShow);
1575 menu.un("show", onShow);
1577 if(g && menu.events["checkchange"]){
1578 groups[g].remove(menu);
1579 menu.un("checkchange", onCheck);
1584 registerCheckable : function(menuItem){
1585 var g = menuItem.group;
1590 groups[g].push(menuItem);
1591 menuItem.on("beforecheckchange", onBeforeCheck);
1596 unregisterCheckable : function(menuItem){
1597 var g = menuItem.group;
1599 groups[g].remove(menuItem);
1600 menuItem.un("beforecheckchange", onBeforeCheck);
1612 * @class Roo.bootstrap.Menu
1613 * @extends Roo.bootstrap.Component
1614 * Bootstrap Menu class - container for MenuItems
1615 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1619 * @param {Object} config The config object
1623 Roo.bootstrap.Menu = function(config){
1624 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1625 if (this.registerMenu) {
1626 Roo.bootstrap.MenuMgr.register(this);
1631 * Fires before this menu is displayed
1632 * @param {Roo.menu.Menu} this
1637 * Fires before this menu is hidden
1638 * @param {Roo.menu.Menu} this
1643 * Fires after this menu is displayed
1644 * @param {Roo.menu.Menu} this
1649 * Fires after this menu is hidden
1650 * @param {Roo.menu.Menu} this
1655 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1656 * @param {Roo.menu.Menu} this
1657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658 * @param {Roo.EventObject} e
1663 * Fires when the mouse is hovering over this menu
1664 * @param {Roo.menu.Menu} this
1665 * @param {Roo.EventObject} e
1666 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1671 * Fires when the mouse exits this menu
1672 * @param {Roo.menu.Menu} this
1673 * @param {Roo.EventObject} e
1674 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1679 * Fires when a menu item contained in this menu is clicked
1680 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1681 * @param {Roo.EventObject} e
1685 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1688 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1692 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1695 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1697 registerMenu : true,
1699 menuItems :false, // stores the menu items..
1705 getChildContainer : function() {
1709 getAutoCreate : function(){
1711 //if (['right'].indexOf(this.align)!==-1) {
1712 // cfg.cn[1].cls += ' pull-right'
1718 cls : 'dropdown-menu' ,
1719 style : 'z-index:1000'
1723 if (this.type === 'submenu') {
1724 cfg.cls = 'submenu active';
1726 if (this.type === 'treeview') {
1727 cfg.cls = 'treeview-menu';
1732 initEvents : function() {
1734 // Roo.log("ADD event");
1735 // Roo.log(this.triggerEl.dom);
1736 this.triggerEl.on('click', this.onTriggerPress, this);
1737 this.triggerEl.addClass('dropdown-toggle');
1738 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1740 this.el.on("mouseover", this.onMouseOver, this);
1741 this.el.on("mouseout", this.onMouseOut, this);
1745 findTargetItem : function(e){
1746 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1750 //Roo.log(t); Roo.log(t.id);
1752 //Roo.log(this.menuitems);
1753 return this.menuitems.get(t.id);
1755 //return this.items.get(t.menuItemId);
1760 onClick : function(e){
1761 Roo.log("menu.onClick");
1762 var t = this.findTargetItem(e);
1763 if(!t || t.isContainer){
1768 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1769 if(t == this.activeItem && t.shouldDeactivate(e)){
1770 this.activeItem.deactivate();
1771 delete this.activeItem;
1775 this.setActiveItem(t, true);
1783 Roo.log('pass click event');
1787 this.fireEvent("click", this, t, e);
1791 onMouseOver : function(e){
1792 var t = this.findTargetItem(e);
1795 // if(t.canActivate && !t.disabled){
1796 // this.setActiveItem(t, true);
1800 this.fireEvent("mouseover", this, e, t);
1802 isVisible : function(){
1803 return !this.hidden;
1805 onMouseOut : function(e){
1806 var t = this.findTargetItem(e);
1809 // if(t == this.activeItem && t.shouldDeactivate(e)){
1810 // this.activeItem.deactivate();
1811 // delete this.activeItem;
1814 this.fireEvent("mouseout", this, e, t);
1819 * Displays this menu relative to another element
1820 * @param {String/HTMLElement/Roo.Element} element The element to align to
1821 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1822 * the element (defaults to this.defaultAlign)
1823 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1825 show : function(el, pos, parentMenu){
1826 this.parentMenu = parentMenu;
1830 this.fireEvent("beforeshow", this);
1831 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1834 * Displays this menu at a specific xy position
1835 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1836 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1838 showAt : function(xy, parentMenu, /* private: */_e){
1839 this.parentMenu = parentMenu;
1844 this.fireEvent("beforeshow", this);
1846 //xy = this.el.adjustForConstraints(xy);
1848 //this.el.setXY(xy);
1850 this.hideMenuItems();
1851 this.hidden = false;
1852 this.triggerEl.addClass('open');
1854 this.fireEvent("show", this);
1860 this.doFocus.defer(50, this);
1864 doFocus : function(){
1866 this.focusEl.focus();
1871 * Hides this menu and optionally all parent menus
1872 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1874 hide : function(deep){
1876 this.hideMenuItems();
1877 if(this.el && this.isVisible()){
1878 this.fireEvent("beforehide", this);
1879 if(this.activeItem){
1880 this.activeItem.deactivate();
1881 this.activeItem = null;
1883 this.triggerEl.removeClass('open');;
1885 this.fireEvent("hide", this);
1887 if(deep === true && this.parentMenu){
1888 this.parentMenu.hide(true);
1892 onTriggerPress : function(e)
1895 Roo.log('trigger press');
1896 //Roo.log(e.getTarget());
1897 // Roo.log(this.triggerEl.dom);
1898 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1901 if (this.isVisible()) {
1905 this.show(this.triggerEl, false, false);
1914 hideMenuItems : function()
1916 //$(backdrop).remove()
1917 Roo.select('.open',true).each(function(aa) {
1919 aa.removeClass('open');
1920 //var parent = getParent($(this))
1921 //var relatedTarget = { relatedTarget: this }
1923 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1924 //if (e.isDefaultPrevented()) return
1925 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1928 addxtypeChild : function (tree, cntr) {
1929 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1931 this.menuitems.add(comp);
1952 * @class Roo.bootstrap.MenuItem
1953 * @extends Roo.bootstrap.Component
1954 * Bootstrap MenuItem class
1955 * @cfg {String} html the menu label
1956 * @cfg {String} href the link
1957 * @cfg {Boolean} preventDefault (true | false) default true
1958 * @cfg {Boolean} isContainer (true | false) default false
1962 * Create a new MenuItem
1963 * @param {Object} config The config object
1967 Roo.bootstrap.MenuItem = function(config){
1968 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1973 * The raw click event for the entire grid.
1974 * @param {Roo.bootstrap.MenuItem} this
1975 * @param {Roo.EventObject} e
1981 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1985 preventDefault: true,
1986 isContainer : false,
1988 getAutoCreate : function(){
1990 if(this.isContainer){
1993 cls: 'dropdown-menu-item'
1999 cls: 'dropdown-menu-item',
2008 if (this.parent().type == 'treeview') {
2009 cfg.cls = 'treeview-menu';
2012 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2013 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2017 initEvents: function() {
2019 //this.el.select('a').on('click', this.onClick, this);
2022 onClick : function(e)
2024 Roo.log('item on click ');
2025 //if(this.preventDefault){
2026 // e.preventDefault();
2028 //this.parent().hideMenuItems();
2030 this.fireEvent('click', this, e);
2049 * @class Roo.bootstrap.MenuSeparator
2050 * @extends Roo.bootstrap.Component
2051 * Bootstrap MenuSeparator class
2054 * Create a new MenuItem
2055 * @param {Object} config The config object
2059 Roo.bootstrap.MenuSeparator = function(config){
2060 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2063 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2065 getAutoCreate : function(){
2084 * @class Roo.bootstrap.Modal
2085 * @extends Roo.bootstrap.Component
2086 * Bootstrap Modal class
2087 * @cfg {String} title Title of dialog
2088 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2089 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2090 * @cfg {Boolean} specificTitle default false
2091 * @cfg {Array} buttons Array of buttons or standard button set..
2092 * @cfg {String} buttonPosition (left|right|center) default right
2093 * @cfg {Boolean} animate default true
2094 * @cfg {Boolean} allow_close default true
2097 * Create a new Modal Dialog
2098 * @param {Object} config The config object
2101 Roo.bootstrap.Modal = function(config){
2102 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2107 * The raw btnclick event for the button
2108 * @param {Roo.EventObject} e
2112 this.buttons = this.buttons || [];
2115 this.tmpl = Roo.factory(this.tmpl);
2120 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2122 title : 'test dialog',
2132 specificTitle: false,
2134 buttonPosition: 'right',
2148 onRender : function(ct, position)
2150 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2153 var cfg = Roo.apply({}, this.getAutoCreate());
2156 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2158 //if (!cfg.name.length) {
2162 cfg.cls += ' ' + this.cls;
2165 cfg.style = this.style;
2167 this.el = Roo.get(document.body).createChild(cfg, position);
2169 //var type = this.el.dom.type;
2174 if(this.tabIndex !== undefined){
2175 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2179 this.bodyEl = this.el.select('.modal-body',true).first();
2180 this.closeEl = this.el.select('.modal-header .close', true).first();
2181 this.footerEl = this.el.select('.modal-footer',true).first();
2182 this.titleEl = this.el.select('.modal-title',true).first();
2186 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2187 this.maskEl.enableDisplayMode("block");
2189 //this.el.addClass("x-dlg-modal");
2191 if (this.buttons.length) {
2192 Roo.each(this.buttons, function(bb) {
2193 b = Roo.apply({}, bb);
2194 b.xns = b.xns || Roo.bootstrap;
2195 b.xtype = b.xtype || 'Button';
2196 if (typeof(b.listeners) == 'undefined') {
2197 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2200 var btn = Roo.factory(b);
2202 btn.onRender(this.el.select('.modal-footer div').first());
2206 // render the children.
2209 if(typeof(this.items) != 'undefined'){
2210 var items = this.items;
2213 for(var i =0;i < items.length;i++) {
2214 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2218 this.items = nitems;
2220 // where are these used - they used to be body/close/footer
2224 //this.el.addClass([this.fieldClass, this.cls]);
2227 getAutoCreate : function(){
2232 html : this.html || ''
2237 cls : 'modal-title',
2241 if(this.specificTitle){
2247 if (this.allow_close) {
2258 style : 'display: none',
2261 cls: "modal-dialog",
2264 cls : "modal-content",
2267 cls : 'modal-header',
2272 cls : 'modal-footer',
2276 cls: 'btn-' + this.buttonPosition
2293 modal.cls += ' fade';
2299 getChildContainer : function() {
2304 getButtonContainer : function() {
2305 return this.el.select('.modal-footer div',true).first();
2308 initEvents : function()
2310 if (this.allow_close) {
2311 this.closeEl.on('click', this.hide, this);
2317 if (!this.rendered) {
2321 this.el.setStyle('display', 'block');
2325 (function(){ _this.el.addClass('in'); }).defer(50);
2327 this.el.addClass('in');
2330 // not sure how we can show data in here..
2332 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2335 Roo.get(document.body).addClass("x-body-masked");
2336 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2338 this.el.setStyle('zIndex', '10001');
2340 this.fireEvent('show', this);
2347 Roo.get(document.body).removeClass("x-body-masked");
2348 this.el.removeClass('in');
2352 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2354 this.el.setStyle('display', 'none');
2357 this.fireEvent('hide', this);
2360 addButton : function(str, cb)
2364 var b = Roo.apply({}, { html : str } );
2365 b.xns = b.xns || Roo.bootstrap;
2366 b.xtype = b.xtype || 'Button';
2367 if (typeof(b.listeners) == 'undefined') {
2368 b.listeners = { click : cb.createDelegate(this) };
2371 var btn = Roo.factory(b);
2373 btn.onRender(this.el.select('.modal-footer div').first());
2379 setDefaultButton : function(btn)
2381 //this.el.select('.modal-footer').()
2383 resizeTo: function(w,h)
2387 setContentSize : function(w, h)
2391 onButtonClick: function(btn,e)
2394 this.fireEvent('btnclick', btn.name, e);
2397 * Set the title of the Dialog
2398 * @param {String} str new Title
2400 setTitle: function(str) {
2401 this.titleEl.dom.innerHTML = str;
2404 * Set the body of the Dialog
2405 * @param {String} str new Title
2407 setBody: function(str) {
2408 this.bodyEl.dom.innerHTML = str;
2411 * Set the body of the Dialog using the template
2412 * @param {Obj} data - apply this data to the template and replace the body contents.
2414 applyBody: function(obj)
2417 Roo.log("Error - using apply Body without a template");
2420 this.tmpl.overwrite(this.bodyEl, obj);
2426 Roo.apply(Roo.bootstrap.Modal, {
2428 * Button config that displays a single OK button
2437 * Button config that displays Yes and No buttons
2453 * Button config that displays OK and Cancel buttons
2468 * Button config that displays Yes, No and Cancel buttons
2491 * messagebox - can be used as a replace
2495 * @class Roo.MessageBox
2496 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2500 Roo.Msg.alert('Status', 'Changes saved successfully.');
2502 // Prompt for user data:
2503 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2505 // process text value...
2509 // Show a dialog using config options:
2511 title:'Save Changes?',
2512 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2513 buttons: Roo.Msg.YESNOCANCEL,
2520 Roo.bootstrap.MessageBox = function(){
2521 var dlg, opt, mask, waitTimer;
2522 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2523 var buttons, activeTextEl, bwidth;
2527 var handleButton = function(button){
2529 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2533 var handleHide = function(){
2535 dlg.el.removeClass(opt.cls);
2538 // Roo.TaskMgr.stop(waitTimer);
2539 // waitTimer = null;
2544 var updateButtons = function(b){
2547 buttons["ok"].hide();
2548 buttons["cancel"].hide();
2549 buttons["yes"].hide();
2550 buttons["no"].hide();
2551 //dlg.footer.dom.style.display = 'none';
2554 dlg.footerEl.dom.style.display = '';
2555 for(var k in buttons){
2556 if(typeof buttons[k] != "function"){
2559 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2560 width += buttons[k].el.getWidth()+15;
2570 var handleEsc = function(d, k, e){
2571 if(opt && opt.closable !== false){
2581 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2582 * @return {Roo.BasicDialog} The BasicDialog element
2584 getDialog : function(){
2586 dlg = new Roo.bootstrap.Modal( {
2589 //constraintoviewport:false,
2591 //collapsible : false,
2596 //buttonAlign:"center",
2597 closeClick : function(){
2598 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2601 handleButton("cancel");
2606 dlg.on("hide", handleHide);
2608 //dlg.addKeyListener(27, handleEsc);
2610 this.buttons = buttons;
2611 var bt = this.buttonText;
2612 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2613 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2614 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2615 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2617 bodyEl = dlg.bodyEl.createChild({
2619 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2620 '<textarea class="roo-mb-textarea"></textarea>' +
2621 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2623 msgEl = bodyEl.dom.firstChild;
2624 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2625 textboxEl.enableDisplayMode();
2626 textboxEl.addKeyListener([10,13], function(){
2627 if(dlg.isVisible() && opt && opt.buttons){
2630 }else if(opt.buttons.yes){
2631 handleButton("yes");
2635 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2636 textareaEl.enableDisplayMode();
2637 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2638 progressEl.enableDisplayMode();
2639 var pf = progressEl.dom.firstChild;
2641 pp = Roo.get(pf.firstChild);
2642 pp.setHeight(pf.offsetHeight);
2650 * Updates the message box body text
2651 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2652 * the XHTML-compliant non-breaking space character '&#160;')
2653 * @return {Roo.MessageBox} This message box
2655 updateText : function(text){
2656 if(!dlg.isVisible() && !opt.width){
2657 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2659 msgEl.innerHTML = text || ' ';
2661 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2662 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2664 Math.min(opt.width || cw , this.maxWidth),
2665 Math.max(opt.minWidth || this.minWidth, bwidth)
2668 activeTextEl.setWidth(w);
2670 if(dlg.isVisible()){
2671 dlg.fixedcenter = false;
2673 // to big, make it scroll. = But as usual stupid IE does not support
2676 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2677 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2678 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2680 bodyEl.dom.style.height = '';
2681 bodyEl.dom.style.overflowY = '';
2684 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2686 bodyEl.dom.style.overflowX = '';
2689 dlg.setContentSize(w, bodyEl.getHeight());
2690 if(dlg.isVisible()){
2691 dlg.fixedcenter = true;
2697 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2698 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2699 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2700 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2701 * @return {Roo.MessageBox} This message box
2703 updateProgress : function(value, text){
2705 this.updateText(text);
2707 if (pp) { // weird bug on my firefox - for some reason this is not defined
2708 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2714 * Returns true if the message box is currently displayed
2715 * @return {Boolean} True if the message box is visible, else false
2717 isVisible : function(){
2718 return dlg && dlg.isVisible();
2722 * Hides the message box if it is displayed
2725 if(this.isVisible()){
2731 * Displays a new message box, or reinitializes an existing message box, based on the config options
2732 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2733 * The following config object properties are supported:
2735 Property Type Description
2736 ---------- --------------- ------------------------------------------------------------------------------------
2737 animEl String/Element An id or Element from which the message box should animate as it opens and
2738 closes (defaults to undefined)
2739 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2740 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2741 closable Boolean False to hide the top-right close button (defaults to true). Note that
2742 progress and wait dialogs will ignore this property and always hide the
2743 close button as they can only be closed programmatically.
2744 cls String A custom CSS class to apply to the message box element
2745 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2746 displayed (defaults to 75)
2747 fn Function A callback function to execute after closing the dialog. The arguments to the
2748 function will be btn (the name of the button that was clicked, if applicable,
2749 e.g. "ok"), and text (the value of the active text field, if applicable).
2750 Progress and wait dialogs will ignore this option since they do not respond to
2751 user actions and can only be closed programmatically, so any required function
2752 should be called by the same code after it closes the dialog.
2753 icon String A CSS class that provides a background image to be used as an icon for
2754 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2755 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2756 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2757 modal Boolean False to allow user interaction with the page while the message box is
2758 displayed (defaults to true)
2759 msg String A string that will replace the existing message box body text (defaults
2760 to the XHTML-compliant non-breaking space character ' ')
2761 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2762 progress Boolean True to display a progress bar (defaults to false)
2763 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2764 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2765 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2766 title String The title text
2767 value String The string value to set into the active textbox element if displayed
2768 wait Boolean True to display a progress bar (defaults to false)
2769 width Number The width of the dialog in pixels
2776 msg: 'Please enter your address:',
2778 buttons: Roo.MessageBox.OKCANCEL,
2781 animEl: 'addAddressBtn'
2784 * @param {Object} config Configuration options
2785 * @return {Roo.MessageBox} This message box
2787 show : function(options)
2790 // this causes nightmares if you show one dialog after another
2791 // especially on callbacks..
2793 if(this.isVisible()){
2796 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2797 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2798 Roo.log("New Dialog Message:" + options.msg )
2799 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2800 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2803 var d = this.getDialog();
2805 d.setTitle(opt.title || " ");
2806 d.closeEl.setDisplayed(opt.closable !== false);
2807 activeTextEl = textboxEl;
2808 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2813 textareaEl.setHeight(typeof opt.multiline == "number" ?
2814 opt.multiline : this.defaultTextHeight);
2815 activeTextEl = textareaEl;
2824 progressEl.setDisplayed(opt.progress === true);
2825 this.updateProgress(0);
2826 activeTextEl.dom.value = opt.value || "";
2828 dlg.setDefaultButton(activeTextEl);
2830 var bs = opt.buttons;
2834 }else if(bs && bs.yes){
2835 db = buttons["yes"];
2837 dlg.setDefaultButton(db);
2839 bwidth = updateButtons(opt.buttons);
2840 this.updateText(opt.msg);
2842 d.el.addClass(opt.cls);
2844 d.proxyDrag = opt.proxyDrag === true;
2845 d.modal = opt.modal !== false;
2846 d.mask = opt.modal !== false ? mask : false;
2848 // force it to the end of the z-index stack so it gets a cursor in FF
2849 document.body.appendChild(dlg.el.dom);
2850 d.animateTarget = null;
2851 d.show(options.animEl);
2857 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2858 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2859 * and closing the message box when the process is complete.
2860 * @param {String} title The title bar text
2861 * @param {String} msg The message box body text
2862 * @return {Roo.MessageBox} This message box
2864 progress : function(title, msg){
2871 minWidth: this.minProgressWidth,
2878 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2879 * If a callback function is passed it will be called after the user clicks the button, and the
2880 * id of the button that was clicked will be passed as the only parameter to the callback
2881 * (could also be the top-right close button).
2882 * @param {String} title The title bar text
2883 * @param {String} msg The message box body text
2884 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2885 * @param {Object} scope (optional) The scope of the callback function
2886 * @return {Roo.MessageBox} This message box
2888 alert : function(title, msg, fn, scope){
2901 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2902 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2903 * You are responsible for closing the message box when the process is complete.
2904 * @param {String} msg The message box body text
2905 * @param {String} title (optional) The title bar text
2906 * @return {Roo.MessageBox} This message box
2908 wait : function(msg, title){
2919 waitTimer = Roo.TaskMgr.start({
2921 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2929 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2930 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2931 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2932 * @param {String} title The title bar text
2933 * @param {String} msg The message box body text
2934 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2935 * @param {Object} scope (optional) The scope of the callback function
2936 * @return {Roo.MessageBox} This message box
2938 confirm : function(title, msg, fn, scope){
2942 buttons: this.YESNO,
2951 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2952 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2953 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2954 * (could also be the top-right close button) and the text that was entered will be passed as the two
2955 * parameters to the callback.
2956 * @param {String} title The title bar text
2957 * @param {String} msg The message box body text
2958 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2959 * @param {Object} scope (optional) The scope of the callback function
2960 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2961 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2962 * @return {Roo.MessageBox} This message box
2964 prompt : function(title, msg, fn, scope, multiline){
2968 buttons: this.OKCANCEL,
2973 multiline: multiline,
2980 * Button config that displays a single OK button
2985 * Button config that displays Yes and No buttons
2988 YESNO : {yes:true, no:true},
2990 * Button config that displays OK and Cancel buttons
2993 OKCANCEL : {ok:true, cancel:true},
2995 * Button config that displays Yes, No and Cancel buttons
2998 YESNOCANCEL : {yes:true, no:true, cancel:true},
3001 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3004 defaultTextHeight : 75,
3006 * The maximum width in pixels of the message box (defaults to 600)
3011 * The minimum width in pixels of the message box (defaults to 100)
3016 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3017 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3020 minProgressWidth : 250,
3022 * An object containing the default button text strings that can be overriden for localized language support.
3023 * Supported properties are: ok, cancel, yes and no.
3024 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3037 * Shorthand for {@link Roo.MessageBox}
3039 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3040 Roo.Msg = Roo.Msg || Roo.MessageBox;
3049 * @class Roo.bootstrap.Navbar
3050 * @extends Roo.bootstrap.Component
3051 * Bootstrap Navbar class
3054 * Create a new Navbar
3055 * @param {Object} config The config object
3059 Roo.bootstrap.Navbar = function(config){
3060 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3064 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3073 getAutoCreate : function(){
3076 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3080 initEvents :function ()
3082 //Roo.log(this.el.select('.navbar-toggle',true));
3083 this.el.select('.navbar-toggle',true).on('click', function() {
3084 // Roo.log('click');
3085 this.el.select('.navbar-collapse',true).toggleClass('in');
3093 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3095 var size = this.el.getSize();
3096 this.maskEl.setSize(size.width, size.height);
3097 this.maskEl.enableDisplayMode("block");
3106 getChildContainer : function()
3108 if (this.el.select('.collapse').getCount()) {
3109 return this.el.select('.collapse',true).first();
3142 * @class Roo.bootstrap.NavSimplebar
3143 * @extends Roo.bootstrap.Navbar
3144 * Bootstrap Sidebar class
3146 * @cfg {Boolean} inverse is inverted color
3148 * @cfg {String} type (nav | pills | tabs)
3149 * @cfg {Boolean} arrangement stacked | justified
3150 * @cfg {String} align (left | right) alignment
3152 * @cfg {Boolean} main (true|false) main nav bar? default false
3153 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3155 * @cfg {String} tag (header|footer|nav|div) default is nav
3161 * Create a new Sidebar
3162 * @param {Object} config The config object
3166 Roo.bootstrap.NavSimplebar = function(config){
3167 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3170 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3186 getAutoCreate : function(){
3190 tag : this.tag || 'div',
3203 this.type = this.type || 'nav';
3204 if (['tabs','pills'].indexOf(this.type)!==-1) {
3205 cfg.cn[0].cls += ' nav-' + this.type
3209 if (this.type!=='nav') {
3210 Roo.log('nav type must be nav/tabs/pills')
3212 cfg.cn[0].cls += ' navbar-nav'
3218 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3219 cfg.cn[0].cls += ' nav-' + this.arrangement;
3223 if (this.align === 'right') {
3224 cfg.cn[0].cls += ' navbar-right';
3228 cfg.cls += ' navbar-inverse';
3255 * @class Roo.bootstrap.NavHeaderbar
3256 * @extends Roo.bootstrap.NavSimplebar
3257 * Bootstrap Sidebar class
3259 * @cfg {String} brand what is brand
3260 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3261 * @cfg {String} brand_href href of the brand
3262 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3263 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3264 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3265 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3268 * Create a new Sidebar
3269 * @param {Object} config The config object
3273 Roo.bootstrap.NavHeaderbar = function(config){
3274 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3278 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3285 desktopCenter : false,
3288 getAutoCreate : function(){
3291 tag: this.nav || 'nav',
3298 if (this.desktopCenter) {
3299 cn.push({cls : 'container', cn : []});
3306 cls: 'navbar-header',
3311 cls: 'navbar-toggle',
3312 'data-toggle': 'collapse',
3317 html: 'Toggle navigation'
3339 cls: 'collapse navbar-collapse',
3343 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3345 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3346 cfg.cls += ' navbar-' + this.position;
3348 // tag can override this..
3350 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3353 if (this.brand !== '') {
3356 href: this.brand_href ? this.brand_href : '#',
3357 cls: 'navbar-brand',
3365 cfg.cls += ' main-nav';
3373 getHeaderChildContainer : function()
3375 if (this.el.select('.navbar-header').getCount()) {
3376 return this.el.select('.navbar-header',true).first();
3379 return this.getChildContainer();
3383 initEvents : function()
3385 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3387 if (this.autohide) {
3392 Roo.get(document).on('scroll',function(e) {
3393 var ns = Roo.get(document).getScroll().top;
3394 var os = prevScroll;
3398 ft.removeClass('slideDown');
3399 ft.addClass('slideUp');
3402 ft.removeClass('slideUp');
3403 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 ||
3889 (this.animateRef && this.href.charAt(0) == '#')
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");
3904 Roo.log("fire event clicked");
3905 if(this.fireEvent('click', this, e) === false){
3909 if(this.tagtype == 'span'){
3913 if(this.animateRef && this.href.charAt(0) == '#'){
3914 this.scrollToElement(e);
3918 var p = this.parent();
3919 if (['tabs','pills'].indexOf(p.type)!==-1) {
3920 if (typeof(p.setActiveItem) !== 'undefined') {
3921 p.setActiveItem(this);
3924 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3925 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3926 // remove the collapsed menu expand...
3927 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3932 isActive: function () {
3935 setActive : function(state, fire, is_was_active)
3937 if (this.active && !state & this.navId) {
3938 this.was_active = true;
3939 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3941 nv.clearWasActive(this);
3945 this.active = state;
3948 this.el.removeClass('active');
3949 } else if (!this.el.hasClass('active')) {
3950 this.el.addClass('active');
3953 this.fireEvent('changed', this, state);
3956 // show a panel if it's registered and related..
3958 if (!this.navId || !this.tabId || !state || is_was_active) {
3962 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3966 var pan = tg.getPanelByName(this.tabId);
3970 // if we can not flip to new panel - go back to old nav highlight..
3971 if (false == tg.showPanel(pan)) {
3972 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3974 var onav = nv.getWasActive();
3976 onav.setActive(true, false, true);
3985 // this should not be here...
3986 setDisabled : function(state)
3988 this.disabled = state;
3990 this.el.removeClass('disabled');
3991 } else if (!this.el.hasClass('disabled')) {
3992 this.el.addClass('disabled');
3998 * Fetch the element to display the tooltip on.
3999 * @return {Roo.Element} defaults to this.el
4001 tooltipEl : function()
4003 return this.el.select('' + this.tagtype + '', true).first();
4006 scrollToElement : function(e)
4008 var c = document.body;
4010 var target = Roo.get(c).select('a[name=' + this.href.replace('#', '') +']', true).first();
4016 var o = target.calcOffsetsTo(c);
4023 this.fireEvent('scrollto', this, options, e);
4025 Roo.get(c).scrollTo('top', options.value, true);
4038 * <span> icon </span>
4039 * <span> text </span>
4040 * <span>badge </span>
4044 * @class Roo.bootstrap.NavSidebarItem
4045 * @extends Roo.bootstrap.NavItem
4046 * Bootstrap Navbar.NavSidebarItem class
4048 * Create a new Navbar Button
4049 * @param {Object} config The config object
4051 Roo.bootstrap.NavSidebarItem = function(config){
4052 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4057 * The raw click event for the entire grid.
4058 * @param {Roo.EventObject} e
4063 * Fires when the active item active state changes
4064 * @param {Roo.bootstrap.NavSidebarItem} this
4065 * @param {boolean} state the new state
4073 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4076 getAutoCreate : function(){
4081 href : this.href || '#',
4093 html : this.html || ''
4098 cfg.cls += ' active';
4102 if (this.glyphicon || this.icon) {
4103 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4104 a.cn.push({ tag : 'i', cls : c }) ;
4109 if (this.badge !== '') {
4110 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4114 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4115 a.cls += 'dropdown-toggle treeview' ;
4139 * @class Roo.bootstrap.Row
4140 * @extends Roo.bootstrap.Component
4141 * Bootstrap Row class (contains columns...)
4145 * @param {Object} config The config object
4148 Roo.bootstrap.Row = function(config){
4149 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4152 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4154 getAutoCreate : function(){
4173 * @class Roo.bootstrap.Element
4174 * @extends Roo.bootstrap.Component
4175 * Bootstrap Element class
4176 * @cfg {String} html contents of the element
4177 * @cfg {String} tag tag of the element
4178 * @cfg {String} cls class of the element
4181 * Create a new Element
4182 * @param {Object} config The config object
4185 Roo.bootstrap.Element = function(config){
4186 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4189 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4196 getAutoCreate : function(){
4209 getValue : function()
4211 return this.el.dom.innerHTML;
4214 setValue : function(value)
4216 this.el.dom.innerHTML = value;
4231 * @class Roo.bootstrap.Pagination
4232 * @extends Roo.bootstrap.Component
4233 * Bootstrap Pagination class
4234 * @cfg {String} size xs | sm | md | lg
4235 * @cfg {Boolean} inverse false | true
4238 * Create a new Pagination
4239 * @param {Object} config The config object
4242 Roo.bootstrap.Pagination = function(config){
4243 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4246 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4252 getAutoCreate : function(){
4258 cfg.cls += ' inverse';
4264 cfg.cls += " " + this.cls;
4282 * @class Roo.bootstrap.PaginationItem
4283 * @extends Roo.bootstrap.Component
4284 * Bootstrap PaginationItem class
4285 * @cfg {String} html text
4286 * @cfg {String} href the link
4287 * @cfg {Boolean} preventDefault (true | false) default true
4288 * @cfg {Boolean} active (true | false) default false
4289 * @cfg {Boolean} disabled default false
4293 * Create a new PaginationItem
4294 * @param {Object} config The config object
4298 Roo.bootstrap.PaginationItem = function(config){
4299 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4304 * The raw click event for the entire grid.
4305 * @param {Roo.EventObject} e
4311 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4315 preventDefault: true,
4320 getAutoCreate : function(){
4326 href : this.href ? this.href : '#',
4327 html : this.html ? this.html : ''
4337 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4341 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4347 initEvents: function() {
4349 this.el.on('click', this.onClick, this);
4352 onClick : function(e)
4354 Roo.log('PaginationItem on click ');
4355 if(this.preventDefault){
4363 this.fireEvent('click', this, e);
4379 * @class Roo.bootstrap.Slider
4380 * @extends Roo.bootstrap.Component
4381 * Bootstrap Slider class
4384 * Create a new Slider
4385 * @param {Object} config The config object
4388 Roo.bootstrap.Slider = function(config){
4389 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4392 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4394 getAutoCreate : function(){
4398 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4402 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4414 * Ext JS Library 1.1.1
4415 * Copyright(c) 2006-2007, Ext JS, LLC.
4417 * Originally Released Under LGPL - original licence link has changed is not relivant.
4420 * <script type="text/javascript">
4425 * @class Roo.grid.ColumnModel
4426 * @extends Roo.util.Observable
4427 * This is the default implementation of a ColumnModel used by the Grid. It defines
4428 * the columns in the grid.
4431 var colModel = new Roo.grid.ColumnModel([
4432 {header: "Ticker", width: 60, sortable: true, locked: true},
4433 {header: "Company Name", width: 150, sortable: true},
4434 {header: "Market Cap.", width: 100, sortable: true},
4435 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4436 {header: "Employees", width: 100, sortable: true, resizable: false}
4441 * The config options listed for this class are options which may appear in each
4442 * individual column definition.
4443 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4445 * @param {Object} config An Array of column config objects. See this class's
4446 * config objects for details.
4448 Roo.grid.ColumnModel = function(config){
4450 * The config passed into the constructor
4452 this.config = config;
4455 // if no id, create one
4456 // if the column does not have a dataIndex mapping,
4457 // map it to the order it is in the config
4458 for(var i = 0, len = config.length; i < len; i++){
4460 if(typeof c.dataIndex == "undefined"){
4463 if(typeof c.renderer == "string"){
4464 c.renderer = Roo.util.Format[c.renderer];
4466 if(typeof c.id == "undefined"){
4469 if(c.editor && c.editor.xtype){
4470 c.editor = Roo.factory(c.editor, Roo.grid);
4472 if(c.editor && c.editor.isFormField){
4473 c.editor = new Roo.grid.GridEditor(c.editor);
4475 this.lookup[c.id] = c;
4479 * The width of columns which have no width specified (defaults to 100)
4482 this.defaultWidth = 100;
4485 * Default sortable of columns which have no sortable specified (defaults to false)
4488 this.defaultSortable = false;
4492 * @event widthchange
4493 * Fires when the width of a column changes.
4494 * @param {ColumnModel} this
4495 * @param {Number} columnIndex The column index
4496 * @param {Number} newWidth The new width
4498 "widthchange": true,
4500 * @event headerchange
4501 * Fires when the text of a header changes.
4502 * @param {ColumnModel} this
4503 * @param {Number} columnIndex The column index
4504 * @param {Number} newText The new header text
4506 "headerchange": true,
4508 * @event hiddenchange
4509 * Fires when a column is hidden or "unhidden".
4510 * @param {ColumnModel} this
4511 * @param {Number} columnIndex The column index
4512 * @param {Boolean} hidden true if hidden, false otherwise
4514 "hiddenchange": true,
4516 * @event columnmoved
4517 * Fires when a column is moved.
4518 * @param {ColumnModel} this
4519 * @param {Number} oldIndex
4520 * @param {Number} newIndex
4522 "columnmoved" : true,
4524 * @event columlockchange
4525 * Fires when a column's locked state is changed
4526 * @param {ColumnModel} this
4527 * @param {Number} colIndex
4528 * @param {Boolean} locked true if locked
4530 "columnlockchange" : true
4532 Roo.grid.ColumnModel.superclass.constructor.call(this);
4534 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4536 * @cfg {String} header The header text to display in the Grid view.
4539 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4540 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4541 * specified, the column's index is used as an index into the Record's data Array.
4544 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4545 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4548 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4549 * Defaults to the value of the {@link #defaultSortable} property.
4550 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4553 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4556 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4559 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4562 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4565 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4566 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4567 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4568 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4571 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4574 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4577 * @cfg {String} cursor (Optional)
4580 * @cfg {String} tooltip (Optional)
4583 * Returns the id of the column at the specified index.
4584 * @param {Number} index The column index
4585 * @return {String} the id
4587 getColumnId : function(index){
4588 return this.config[index].id;
4592 * Returns the column for a specified id.
4593 * @param {String} id The column id
4594 * @return {Object} the column
4596 getColumnById : function(id){
4597 return this.lookup[id];
4602 * Returns the column for a specified dataIndex.
4603 * @param {String} dataIndex The column dataIndex
4604 * @return {Object|Boolean} the column or false if not found
4606 getColumnByDataIndex: function(dataIndex){
4607 var index = this.findColumnIndex(dataIndex);
4608 return index > -1 ? this.config[index] : false;
4612 * Returns the index for a specified column id.
4613 * @param {String} id The column id
4614 * @return {Number} the index, or -1 if not found
4616 getIndexById : function(id){
4617 for(var i = 0, len = this.config.length; i < len; i++){
4618 if(this.config[i].id == id){
4626 * Returns the index for a specified column dataIndex.
4627 * @param {String} dataIndex The column dataIndex
4628 * @return {Number} the index, or -1 if not found
4631 findColumnIndex : function(dataIndex){
4632 for(var i = 0, len = this.config.length; i < len; i++){
4633 if(this.config[i].dataIndex == dataIndex){
4641 moveColumn : function(oldIndex, newIndex){
4642 var c = this.config[oldIndex];
4643 this.config.splice(oldIndex, 1);
4644 this.config.splice(newIndex, 0, c);
4645 this.dataMap = null;
4646 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4649 isLocked : function(colIndex){
4650 return this.config[colIndex].locked === true;
4653 setLocked : function(colIndex, value, suppressEvent){
4654 if(this.isLocked(colIndex) == value){
4657 this.config[colIndex].locked = value;
4659 this.fireEvent("columnlockchange", this, colIndex, value);
4663 getTotalLockedWidth : function(){
4665 for(var i = 0; i < this.config.length; i++){
4666 if(this.isLocked(i) && !this.isHidden(i)){
4667 this.totalWidth += this.getColumnWidth(i);
4673 getLockedCount : function(){
4674 for(var i = 0, len = this.config.length; i < len; i++){
4675 if(!this.isLocked(i)){
4682 * Returns the number of columns.
4685 getColumnCount : function(visibleOnly){
4686 if(visibleOnly === true){
4688 for(var i = 0, len = this.config.length; i < len; i++){
4689 if(!this.isHidden(i)){
4695 return this.config.length;
4699 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4700 * @param {Function} fn
4701 * @param {Object} scope (optional)
4702 * @return {Array} result
4704 getColumnsBy : function(fn, scope){
4706 for(var i = 0, len = this.config.length; i < len; i++){
4707 var c = this.config[i];
4708 if(fn.call(scope||this, c, i) === true){
4716 * Returns true if the specified column is sortable.
4717 * @param {Number} col The column index
4720 isSortable : function(col){
4721 if(typeof this.config[col].sortable == "undefined"){
4722 return this.defaultSortable;
4724 return this.config[col].sortable;
4728 * Returns the rendering (formatting) function defined for the column.
4729 * @param {Number} col The column index.
4730 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4732 getRenderer : function(col){
4733 if(!this.config[col].renderer){
4734 return Roo.grid.ColumnModel.defaultRenderer;
4736 return this.config[col].renderer;
4740 * Sets the rendering (formatting) function for a column.
4741 * @param {Number} col The column index
4742 * @param {Function} fn The function to use to process the cell's raw data
4743 * to return HTML markup for the grid view. The render function is called with
4744 * the following parameters:<ul>
4745 * <li>Data value.</li>
4746 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4747 * <li>css A CSS style string to apply to the table cell.</li>
4748 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4749 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4750 * <li>Row index</li>
4751 * <li>Column index</li>
4752 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4754 setRenderer : function(col, fn){
4755 this.config[col].renderer = fn;
4759 * Returns the width for the specified column.
4760 * @param {Number} col The column index
4763 getColumnWidth : function(col){
4764 return this.config[col].width * 1 || this.defaultWidth;
4768 * Sets the width for a column.
4769 * @param {Number} col The column index
4770 * @param {Number} width The new width
4772 setColumnWidth : function(col, width, suppressEvent){
4773 this.config[col].width = width;
4774 this.totalWidth = null;
4776 this.fireEvent("widthchange", this, col, width);
4781 * Returns the total width of all columns.
4782 * @param {Boolean} includeHidden True to include hidden column widths
4785 getTotalWidth : function(includeHidden){
4786 if(!this.totalWidth){
4787 this.totalWidth = 0;
4788 for(var i = 0, len = this.config.length; i < len; i++){
4789 if(includeHidden || !this.isHidden(i)){
4790 this.totalWidth += this.getColumnWidth(i);
4794 return this.totalWidth;
4798 * Returns the header for the specified column.
4799 * @param {Number} col The column index
4802 getColumnHeader : function(col){
4803 return this.config[col].header;
4807 * Sets the header for a column.
4808 * @param {Number} col The column index
4809 * @param {String} header The new header
4811 setColumnHeader : function(col, header){
4812 this.config[col].header = header;
4813 this.fireEvent("headerchange", this, col, header);
4817 * Returns the tooltip for the specified column.
4818 * @param {Number} col The column index
4821 getColumnTooltip : function(col){
4822 return this.config[col].tooltip;
4825 * Sets the tooltip for a column.
4826 * @param {Number} col The column index
4827 * @param {String} tooltip The new tooltip
4829 setColumnTooltip : function(col, tooltip){
4830 this.config[col].tooltip = tooltip;
4834 * Returns the dataIndex for the specified column.
4835 * @param {Number} col The column index
4838 getDataIndex : function(col){
4839 return this.config[col].dataIndex;
4843 * Sets the dataIndex for a column.
4844 * @param {Number} col The column index
4845 * @param {Number} dataIndex The new dataIndex
4847 setDataIndex : function(col, dataIndex){
4848 this.config[col].dataIndex = dataIndex;
4854 * Returns true if the cell is editable.
4855 * @param {Number} colIndex The column index
4856 * @param {Number} rowIndex The row index
4859 isCellEditable : function(colIndex, rowIndex){
4860 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4864 * Returns the editor defined for the cell/column.
4865 * return false or null to disable editing.
4866 * @param {Number} colIndex The column index
4867 * @param {Number} rowIndex The row index
4870 getCellEditor : function(colIndex, rowIndex){
4871 return this.config[colIndex].editor;
4875 * Sets if a column is editable.
4876 * @param {Number} col The column index
4877 * @param {Boolean} editable True if the column is editable
4879 setEditable : function(col, editable){
4880 this.config[col].editable = editable;
4885 * Returns true if the column is hidden.
4886 * @param {Number} colIndex The column index
4889 isHidden : function(colIndex){
4890 return this.config[colIndex].hidden;
4895 * Returns true if the column width cannot be changed
4897 isFixed : function(colIndex){
4898 return this.config[colIndex].fixed;
4902 * Returns true if the column can be resized
4905 isResizable : function(colIndex){
4906 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4909 * Sets if a column is hidden.
4910 * @param {Number} colIndex The column index
4911 * @param {Boolean} hidden True if the column is hidden
4913 setHidden : function(colIndex, hidden){
4914 this.config[colIndex].hidden = hidden;
4915 this.totalWidth = null;
4916 this.fireEvent("hiddenchange", this, colIndex, hidden);
4920 * Sets the editor for a column.
4921 * @param {Number} col The column index
4922 * @param {Object} editor The editor object
4924 setEditor : function(col, editor){
4925 this.config[col].editor = editor;
4929 Roo.grid.ColumnModel.defaultRenderer = function(value){
4930 if(typeof value == "string" && value.length < 1){
4936 // Alias for backwards compatibility
4937 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4940 * Ext JS Library 1.1.1
4941 * Copyright(c) 2006-2007, Ext JS, LLC.
4943 * Originally Released Under LGPL - original licence link has changed is not relivant.
4946 * <script type="text/javascript">
4950 * @class Roo.LoadMask
4951 * A simple utility class for generically masking elements while loading data. If the element being masked has
4952 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4953 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4954 * element's UpdateManager load indicator and will be destroyed after the initial load.
4956 * Create a new LoadMask
4957 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4958 * @param {Object} config The config object
4960 Roo.LoadMask = function(el, config){
4961 this.el = Roo.get(el);
4962 Roo.apply(this, config);
4964 this.store.on('beforeload', this.onBeforeLoad, this);
4965 this.store.on('load', this.onLoad, this);
4966 this.store.on('loadexception', this.onLoadException, this);
4967 this.removeMask = false;
4969 var um = this.el.getUpdateManager();
4970 um.showLoadIndicator = false; // disable the default indicator
4971 um.on('beforeupdate', this.onBeforeLoad, this);
4972 um.on('update', this.onLoad, this);
4973 um.on('failure', this.onLoad, this);
4974 this.removeMask = true;
4978 Roo.LoadMask.prototype = {
4980 * @cfg {Boolean} removeMask
4981 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4982 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4986 * The text to display in a centered loading message box (defaults to 'Loading...')
4990 * @cfg {String} msgCls
4991 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4993 msgCls : 'x-mask-loading',
4996 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5002 * Disables the mask to prevent it from being displayed
5004 disable : function(){
5005 this.disabled = true;
5009 * Enables the mask so that it can be displayed
5011 enable : function(){
5012 this.disabled = false;
5015 onLoadException : function()
5019 if (typeof(arguments[3]) != 'undefined') {
5020 Roo.MessageBox.alert("Error loading",arguments[3]);
5024 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5025 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5034 this.el.unmask(this.removeMask);
5039 this.el.unmask(this.removeMask);
5043 onBeforeLoad : function(){
5045 this.el.mask(this.msg, this.msgCls);
5050 destroy : function(){
5052 this.store.un('beforeload', this.onBeforeLoad, this);
5053 this.store.un('load', this.onLoad, this);
5054 this.store.un('loadexception', this.onLoadException, this);
5056 var um = this.el.getUpdateManager();
5057 um.un('beforeupdate', this.onBeforeLoad, this);
5058 um.un('update', this.onLoad, this);
5059 um.un('failure', this.onLoad, this);
5070 * @class Roo.bootstrap.Table
5071 * @extends Roo.bootstrap.Component
5072 * Bootstrap Table class
5073 * @cfg {String} cls table class
5074 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5075 * @cfg {String} bgcolor Specifies the background color for a table
5076 * @cfg {Number} border Specifies whether the table cells should have borders or not
5077 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5078 * @cfg {Number} cellspacing Specifies the space between cells
5079 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5080 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5081 * @cfg {String} sortable Specifies that the table should be sortable
5082 * @cfg {String} summary Specifies a summary of the content of a table
5083 * @cfg {Number} width Specifies the width of a table
5084 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5086 * @cfg {boolean} striped Should the rows be alternative striped
5087 * @cfg {boolean} bordered Add borders to the table
5088 * @cfg {boolean} hover Add hover highlighting
5089 * @cfg {boolean} condensed Format condensed
5090 * @cfg {boolean} responsive Format condensed
5091 * @cfg {Boolean} loadMask (true|false) default false
5092 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5093 * @cfg {Boolean} thead (true|false) generate thead, default true
5094 * @cfg {Boolean} RowSelection (true|false) default false
5095 * @cfg {Boolean} CellSelection (true|false) default false
5096 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5100 * Create a new Table
5101 * @param {Object} config The config object
5104 Roo.bootstrap.Table = function(config){
5105 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5108 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5109 this.sm = this.selModel;
5110 this.sm.xmodule = this.xmodule || false;
5112 if (this.cm && typeof(this.cm.config) == 'undefined') {
5113 this.colModel = new Roo.grid.ColumnModel(this.cm);
5114 this.cm = this.colModel;
5115 this.cm.xmodule = this.xmodule || false;
5118 this.store= Roo.factory(this.store, Roo.data);
5119 this.ds = this.store;
5120 this.ds.xmodule = this.xmodule || false;
5123 if (this.footer && this.store) {
5124 this.footer.dataSource = this.ds;
5125 this.footer = Roo.factory(this.footer);
5132 * Fires when a cell is clicked
5133 * @param {Roo.bootstrap.Table} this
5134 * @param {Roo.Element} el
5135 * @param {Number} rowIndex
5136 * @param {Number} columnIndex
5137 * @param {Roo.EventObject} e
5141 * @event celldblclick
5142 * Fires when a cell is double clicked
5143 * @param {Roo.bootstrap.Table} this
5144 * @param {Roo.Element} el
5145 * @param {Number} rowIndex
5146 * @param {Number} columnIndex
5147 * @param {Roo.EventObject} e
5149 "celldblclick" : true,
5152 * Fires when a row is clicked
5153 * @param {Roo.bootstrap.Table} this
5154 * @param {Roo.Element} el
5155 * @param {Number} rowIndex
5156 * @param {Roo.EventObject} e
5160 * @event rowdblclick
5161 * Fires when a row is double clicked
5162 * @param {Roo.bootstrap.Table} this
5163 * @param {Roo.Element} el
5164 * @param {Number} rowIndex
5165 * @param {Roo.EventObject} e
5167 "rowdblclick" : true,
5170 * Fires when a mouseover occur
5171 * @param {Roo.bootstrap.Table} this
5172 * @param {Roo.Element} el
5173 * @param {Number} rowIndex
5174 * @param {Number} columnIndex
5175 * @param {Roo.EventObject} e
5180 * Fires when a mouseout occur
5181 * @param {Roo.bootstrap.Table} this
5182 * @param {Roo.Element} el
5183 * @param {Number} rowIndex
5184 * @param {Number} columnIndex
5185 * @param {Roo.EventObject} e
5190 * Fires when a row is rendered, so you can change add a style to it.
5191 * @param {Roo.bootstrap.Table} this
5192 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5196 * @event rowsrendered
5197 * Fires when all the rows have been rendered
5198 * @param {Roo.bootstrap.Table} this
5200 'rowsrendered' : true
5205 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5229 RowSelection : false,
5230 CellSelection : false,
5233 // Roo.Element - the tbody
5236 getAutoCreate : function(){
5237 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5246 cfg.cls += ' table-striped';
5250 cfg.cls += ' table-hover';
5252 if (this.bordered) {
5253 cfg.cls += ' table-bordered';
5255 if (this.condensed) {
5256 cfg.cls += ' table-condensed';
5258 if (this.responsive) {
5259 cfg.cls += ' table-responsive';
5263 cfg.cls+= ' ' +this.cls;
5266 // this lot should be simplifed...
5269 cfg.align=this.align;
5272 cfg.bgcolor=this.bgcolor;
5275 cfg.border=this.border;
5277 if (this.cellpadding) {
5278 cfg.cellpadding=this.cellpadding;
5280 if (this.cellspacing) {
5281 cfg.cellspacing=this.cellspacing;
5284 cfg.frame=this.frame;
5287 cfg.rules=this.rules;
5289 if (this.sortable) {
5290 cfg.sortable=this.sortable;
5293 cfg.summary=this.summary;
5296 cfg.width=this.width;
5299 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5302 if(this.store || this.cm){
5304 cfg.cn.push(this.renderHeader());
5307 cfg.cn.push(this.renderBody());
5310 cfg.cn.push(this.renderFooter());
5313 cfg.cls+= ' TableGrid';
5316 return { cn : [ cfg ] };
5319 initEvents : function()
5321 if(!this.store || !this.cm){
5325 //Roo.log('initEvents with ds!!!!');
5327 this.mainBody = this.el.select('tbody', true).first();
5332 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5333 e.on('click', _this.sort, _this);
5336 this.el.on("click", this.onClick, this);
5337 this.el.on("dblclick", this.onDblClick, this);
5339 // why is this done????? = it breaks dialogs??
5340 //this.parent().el.setStyle('position', 'relative');
5344 this.footer.parentId = this.id;
5345 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5348 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5350 this.store.on('load', this.onLoad, this);
5351 this.store.on('beforeload', this.onBeforeLoad, this);
5352 this.store.on('update', this.onUpdate, this);
5353 this.store.on('add', this.onAdd, this);
5357 onMouseover : function(e, el)
5359 var cell = Roo.get(el);
5365 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5366 cell = cell.findParent('td', false, true);
5369 var row = cell.findParent('tr', false, true);
5370 var cellIndex = cell.dom.cellIndex;
5371 var rowIndex = row.dom.rowIndex - 1; // start from 0
5373 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5377 onMouseout : function(e, el)
5379 var cell = Roo.get(el);
5385 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5386 cell = cell.findParent('td', false, true);
5389 var row = cell.findParent('tr', false, true);
5390 var cellIndex = cell.dom.cellIndex;
5391 var rowIndex = row.dom.rowIndex - 1; // start from 0
5393 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5397 onClick : function(e, el)
5399 var cell = Roo.get(el);
5401 if(!cell || (!this.CellSelection && !this.RowSelection)){
5405 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5406 cell = cell.findParent('td', false, true);
5409 if(!cell || typeof(cell) == 'undefined'){
5413 var row = cell.findParent('tr', false, true);
5415 if(!row || typeof(row) == 'undefined'){
5419 var cellIndex = cell.dom.cellIndex;
5420 var rowIndex = this.getRowIndex(row);
5422 if(this.CellSelection){
5423 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5426 if(this.RowSelection){
5427 this.fireEvent('rowclick', this, row, rowIndex, e);
5433 onDblClick : function(e,el)
5435 var cell = Roo.get(el);
5437 if(!cell || (!this.CellSelection && !this.RowSelection)){
5441 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5442 cell = cell.findParent('td', false, true);
5445 if(!cell || typeof(cell) == 'undefined'){
5449 var row = cell.findParent('tr', false, true);
5451 if(!row || typeof(row) == 'undefined'){
5455 var cellIndex = cell.dom.cellIndex;
5456 var rowIndex = this.getRowIndex(row);
5458 if(this.CellSelection){
5459 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5462 if(this.RowSelection){
5463 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5467 sort : function(e,el)
5469 var col = Roo.get(el);
5471 if(!col.hasClass('sortable')){
5475 var sort = col.attr('sort');
5478 if(col.hasClass('glyphicon-arrow-up')){
5482 this.store.sortInfo = {field : sort, direction : dir};
5485 Roo.log("calling footer first");
5486 this.footer.onClick('first');
5489 this.store.load({ params : { start : 0 } });
5493 renderHeader : function()
5502 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5504 var config = cm.config[i];
5509 html: cm.getColumnHeader(i)
5512 if(typeof(config.tooltip) != 'undefined'){
5513 c.tooltip = config.tooltip;
5516 if(typeof(config.colspan) != 'undefined'){
5517 c.colspan = config.colspan;
5520 if(typeof(config.hidden) != 'undefined' && config.hidden){
5521 c.style += ' display:none;';
5524 if(typeof(config.dataIndex) != 'undefined'){
5525 c.sort = config.dataIndex;
5528 if(typeof(config.sortable) != 'undefined' && config.sortable){
5532 if(typeof(config.align) != 'undefined' && config.align.length){
5533 c.style += ' text-align:' + config.align + ';';
5536 if(typeof(config.width) != 'undefined'){
5537 c.style += ' width:' + config.width + 'px;';
5546 renderBody : function()
5556 colspan : this.cm.getColumnCount()
5566 renderFooter : function()
5576 colspan : this.cm.getColumnCount()
5590 Roo.log('ds onload');
5595 var ds = this.store;
5597 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5598 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5600 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5601 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5604 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5605 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5609 var tbody = this.mainBody;
5611 if(ds.getCount() > 0){
5612 ds.data.each(function(d,rowIndex){
5613 var row = this.renderRow(cm, ds, rowIndex);
5615 tbody.createChild(row);
5619 if(row.cellObjects.length){
5620 Roo.each(row.cellObjects, function(r){
5621 _this.renderCellObject(r);
5628 Roo.each(this.el.select('tbody td', true).elements, function(e){
5629 e.on('mouseover', _this.onMouseover, _this);
5632 Roo.each(this.el.select('tbody td', true).elements, function(e){
5633 e.on('mouseout', _this.onMouseout, _this);
5635 this.fireEvent('rowsrendered', this);
5636 //if(this.loadMask){
5637 // this.maskEl.hide();
5642 onUpdate : function(ds,record)
5644 this.refreshRow(record);
5647 onRemove : function(ds, record, index, isUpdate){
5648 if(isUpdate !== true){
5649 this.fireEvent("beforerowremoved", this, index, record);
5651 var bt = this.mainBody.dom;
5653 var rows = this.el.select('tbody > tr', true).elements;
5655 if(typeof(rows[index]) != 'undefined'){
5656 bt.removeChild(rows[index].dom);
5659 // if(bt.rows[index]){
5660 // bt.removeChild(bt.rows[index]);
5663 if(isUpdate !== true){
5664 //this.stripeRows(index);
5665 //this.syncRowHeights(index, index);
5667 this.fireEvent("rowremoved", this, index, record);
5671 onAdd : function(ds, records, rowIndex)
5673 //Roo.log('on Add called');
5674 // - note this does not handle multiple adding very well..
5675 var bt = this.mainBody.dom;
5676 for (var i =0 ; i < records.length;i++) {
5677 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5678 //Roo.log(records[i]);
5679 //Roo.log(this.store.getAt(rowIndex+i));
5680 this.insertRow(this.store, rowIndex + i, false);
5687 refreshRow : function(record){
5688 var ds = this.store, index;
5689 if(typeof record == 'number'){
5691 record = ds.getAt(index);
5693 index = ds.indexOf(record);
5695 this.insertRow(ds, index, true);
5696 this.onRemove(ds, record, index+1, true);
5697 //this.syncRowHeights(index, index);
5699 this.fireEvent("rowupdated", this, index, record);
5702 insertRow : function(dm, rowIndex, isUpdate){
5705 this.fireEvent("beforerowsinserted", this, rowIndex);
5707 //var s = this.getScrollState();
5708 var row = this.renderRow(this.cm, this.store, rowIndex);
5709 // insert before rowIndex..
5710 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5714 if(row.cellObjects.length){
5715 Roo.each(row.cellObjects, function(r){
5716 _this.renderCellObject(r);
5721 this.fireEvent("rowsinserted", this, rowIndex);
5722 //this.syncRowHeights(firstRow, lastRow);
5723 //this.stripeRows(firstRow);
5730 getRowDom : function(rowIndex)
5732 var rows = this.el.select('tbody > tr', true).elements;
5734 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5737 // returns the object tree for a tr..
5740 renderRow : function(cm, ds, rowIndex)
5743 var d = ds.getAt(rowIndex);
5750 var cellObjects = [];
5752 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5753 var config = cm.config[i];
5755 var renderer = cm.getRenderer(i);
5759 if(typeof(renderer) !== 'undefined'){
5760 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5762 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5763 // and are rendered into the cells after the row is rendered - using the id for the element.
5765 if(typeof(value) === 'object'){
5775 rowIndex : rowIndex,
5780 this.fireEvent('rowclass', this, rowcfg);
5784 cls : rowcfg.rowClass,
5786 html: (typeof(value) === 'object') ? '' : value
5793 if(typeof(config.colspan) != 'undefined'){
5794 td.colspan = config.colspan;
5797 if(typeof(config.hidden) != 'undefined' && config.hidden){
5798 td.style += ' display:none;';
5801 if(typeof(config.align) != 'undefined' && config.align.length){
5802 td.style += ' text-align:' + config.align + ';';
5805 if(typeof(config.width) != 'undefined'){
5806 td.style += ' width:' + config.width + 'px;';
5809 if(typeof(config.cursor) != 'undefined'){
5810 td.style += ' cursor:' + config.cursor + ';';
5817 row.cellObjects = cellObjects;
5825 onBeforeLoad : function()
5827 //Roo.log('ds onBeforeLoad');
5831 //if(this.loadMask){
5832 // this.maskEl.show();
5840 this.el.select('tbody', true).first().dom.innerHTML = '';
5843 * Show or hide a row.
5844 * @param {Number} rowIndex to show or hide
5845 * @param {Boolean} state hide
5847 setRowVisibility : function(rowIndex, state)
5849 var bt = this.mainBody.dom;
5851 var rows = this.el.select('tbody > tr', true).elements;
5853 if(typeof(rows[rowIndex]) == 'undefined'){
5856 rows[rowIndex].dom.style.display = state ? '' : 'none';
5860 getSelectionModel : function(){
5862 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5864 return this.selModel;
5867 * Render the Roo.bootstrap object from renderder
5869 renderCellObject : function(r)
5873 var t = r.cfg.render(r.container);
5876 Roo.each(r.cfg.cn, function(c){
5878 container: t.getChildContainer(),
5881 _this.renderCellObject(child);
5886 getRowIndex : function(row)
5890 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5913 * @class Roo.bootstrap.TableCell
5914 * @extends Roo.bootstrap.Component
5915 * Bootstrap TableCell class
5916 * @cfg {String} html cell contain text
5917 * @cfg {String} cls cell class
5918 * @cfg {String} tag cell tag (td|th) default td
5919 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5920 * @cfg {String} align Aligns the content in a cell
5921 * @cfg {String} axis Categorizes cells
5922 * @cfg {String} bgcolor Specifies the background color of a cell
5923 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5924 * @cfg {Number} colspan Specifies the number of columns a cell should span
5925 * @cfg {String} headers Specifies one or more header cells a cell is related to
5926 * @cfg {Number} height Sets the height of a cell
5927 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5928 * @cfg {Number} rowspan Sets the number of rows a cell should span
5929 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5930 * @cfg {String} valign Vertical aligns the content in a cell
5931 * @cfg {Number} width Specifies the width of a cell
5934 * Create a new TableCell
5935 * @param {Object} config The config object
5938 Roo.bootstrap.TableCell = function(config){
5939 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5942 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5962 getAutoCreate : function(){
5963 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5983 cfg.align=this.align
5989 cfg.bgcolor=this.bgcolor
5992 cfg.charoff=this.charoff
5995 cfg.colspan=this.colspan
5998 cfg.headers=this.headers
6001 cfg.height=this.height
6004 cfg.nowrap=this.nowrap
6007 cfg.rowspan=this.rowspan
6010 cfg.scope=this.scope
6013 cfg.valign=this.valign
6016 cfg.width=this.width
6035 * @class Roo.bootstrap.TableRow
6036 * @extends Roo.bootstrap.Component
6037 * Bootstrap TableRow class
6038 * @cfg {String} cls row class
6039 * @cfg {String} align Aligns the content in a table row
6040 * @cfg {String} bgcolor Specifies a background color for a table row
6041 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6042 * @cfg {String} valign Vertical aligns the content in a table row
6045 * Create a new TableRow
6046 * @param {Object} config The config object
6049 Roo.bootstrap.TableRow = function(config){
6050 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6053 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6061 getAutoCreate : function(){
6062 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6072 cfg.align = this.align;
6075 cfg.bgcolor = this.bgcolor;
6078 cfg.charoff = this.charoff;
6081 cfg.valign = this.valign;
6099 * @class Roo.bootstrap.TableBody
6100 * @extends Roo.bootstrap.Component
6101 * Bootstrap TableBody class
6102 * @cfg {String} cls element class
6103 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6104 * @cfg {String} align Aligns the content inside the element
6105 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6106 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6109 * Create a new TableBody
6110 * @param {Object} config The config object
6113 Roo.bootstrap.TableBody = function(config){
6114 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6117 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6125 getAutoCreate : function(){
6126 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6140 cfg.align = this.align;
6143 cfg.charoff = this.charoff;
6146 cfg.valign = this.valign;
6153 // initEvents : function()
6160 // this.store = Roo.factory(this.store, Roo.data);
6161 // this.store.on('load', this.onLoad, this);
6163 // this.store.load();
6167 // onLoad: function ()
6169 // this.fireEvent('load', this);
6179 * Ext JS Library 1.1.1
6180 * Copyright(c) 2006-2007, Ext JS, LLC.
6182 * Originally Released Under LGPL - original licence link has changed is not relivant.
6185 * <script type="text/javascript">
6188 // as we use this in bootstrap.
6189 Roo.namespace('Roo.form');
6191 * @class Roo.form.Action
6192 * Internal Class used to handle form actions
6194 * @param {Roo.form.BasicForm} el The form element or its id
6195 * @param {Object} config Configuration options
6200 // define the action interface
6201 Roo.form.Action = function(form, options){
6203 this.options = options || {};
6206 * Client Validation Failed
6209 Roo.form.Action.CLIENT_INVALID = 'client';
6211 * Server Validation Failed
6214 Roo.form.Action.SERVER_INVALID = 'server';
6216 * Connect to Server Failed
6219 Roo.form.Action.CONNECT_FAILURE = 'connect';
6221 * Reading Data from Server Failed
6224 Roo.form.Action.LOAD_FAILURE = 'load';
6226 Roo.form.Action.prototype = {
6228 failureType : undefined,
6229 response : undefined,
6233 run : function(options){
6238 success : function(response){
6243 handleResponse : function(response){
6247 // default connection failure
6248 failure : function(response){
6250 this.response = response;
6251 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6252 this.form.afterAction(this, false);
6255 processResponse : function(response){
6256 this.response = response;
6257 if(!response.responseText){
6260 this.result = this.handleResponse(response);
6264 // utility functions used internally
6265 getUrl : function(appendParams){
6266 var url = this.options.url || this.form.url || this.form.el.dom.action;
6268 var p = this.getParams();
6270 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6276 getMethod : function(){
6277 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6280 getParams : function(){
6281 var bp = this.form.baseParams;
6282 var p = this.options.params;
6284 if(typeof p == "object"){
6285 p = Roo.urlEncode(Roo.applyIf(p, bp));
6286 }else if(typeof p == 'string' && bp){
6287 p += '&' + Roo.urlEncode(bp);
6290 p = Roo.urlEncode(bp);
6295 createCallback : function(){
6297 success: this.success,
6298 failure: this.failure,
6300 timeout: (this.form.timeout*1000),
6301 upload: this.form.fileUpload ? this.success : undefined
6306 Roo.form.Action.Submit = function(form, options){
6307 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6310 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6313 haveProgress : false,
6314 uploadComplete : false,
6316 // uploadProgress indicator.
6317 uploadProgress : function()
6319 if (!this.form.progressUrl) {
6323 if (!this.haveProgress) {
6324 Roo.MessageBox.progress("Uploading", "Uploading");
6326 if (this.uploadComplete) {
6327 Roo.MessageBox.hide();
6331 this.haveProgress = true;
6333 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6335 var c = new Roo.data.Connection();
6337 url : this.form.progressUrl,
6342 success : function(req){
6343 //console.log(data);
6347 rdata = Roo.decode(req.responseText)
6349 Roo.log("Invalid data from server..");
6353 if (!rdata || !rdata.success) {
6355 Roo.MessageBox.alert(Roo.encode(rdata));
6358 var data = rdata.data;
6360 if (this.uploadComplete) {
6361 Roo.MessageBox.hide();
6366 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6367 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6370 this.uploadProgress.defer(2000,this);
6373 failure: function(data) {
6374 Roo.log('progress url failed ');
6385 // run get Values on the form, so it syncs any secondary forms.
6386 this.form.getValues();
6388 var o = this.options;
6389 var method = this.getMethod();
6390 var isPost = method == 'POST';
6391 if(o.clientValidation === false || this.form.isValid()){
6393 if (this.form.progressUrl) {
6394 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6395 (new Date() * 1) + '' + Math.random());
6400 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6401 form:this.form.el.dom,
6402 url:this.getUrl(!isPost),
6404 params:isPost ? this.getParams() : null,
6405 isUpload: this.form.fileUpload
6408 this.uploadProgress();
6410 }else if (o.clientValidation !== false){ // client validation failed
6411 this.failureType = Roo.form.Action.CLIENT_INVALID;
6412 this.form.afterAction(this, false);
6416 success : function(response)
6418 this.uploadComplete= true;
6419 if (this.haveProgress) {
6420 Roo.MessageBox.hide();
6424 var result = this.processResponse(response);
6425 if(result === true || result.success){
6426 this.form.afterAction(this, true);
6430 this.form.markInvalid(result.errors);
6431 this.failureType = Roo.form.Action.SERVER_INVALID;
6433 this.form.afterAction(this, false);
6435 failure : function(response)
6437 this.uploadComplete= true;
6438 if (this.haveProgress) {
6439 Roo.MessageBox.hide();
6442 this.response = response;
6443 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6444 this.form.afterAction(this, false);
6447 handleResponse : function(response){
6448 if(this.form.errorReader){
6449 var rs = this.form.errorReader.read(response);
6452 for(var i = 0, len = rs.records.length; i < len; i++) {
6453 var r = rs.records[i];
6457 if(errors.length < 1){
6461 success : rs.success,
6467 ret = Roo.decode(response.responseText);
6471 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6481 Roo.form.Action.Load = function(form, options){
6482 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6483 this.reader = this.form.reader;
6486 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6491 Roo.Ajax.request(Roo.apply(
6492 this.createCallback(), {
6493 method:this.getMethod(),
6494 url:this.getUrl(false),
6495 params:this.getParams()
6499 success : function(response){
6501 var result = this.processResponse(response);
6502 if(result === true || !result.success || !result.data){
6503 this.failureType = Roo.form.Action.LOAD_FAILURE;
6504 this.form.afterAction(this, false);
6507 this.form.clearInvalid();
6508 this.form.setValues(result.data);
6509 this.form.afterAction(this, true);
6512 handleResponse : function(response){
6513 if(this.form.reader){
6514 var rs = this.form.reader.read(response);
6515 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6517 success : rs.success,
6521 return Roo.decode(response.responseText);
6525 Roo.form.Action.ACTION_TYPES = {
6526 'load' : Roo.form.Action.Load,
6527 'submit' : Roo.form.Action.Submit
6536 * @class Roo.bootstrap.Form
6537 * @extends Roo.bootstrap.Component
6538 * Bootstrap Form class
6539 * @cfg {String} method GET | POST (default POST)
6540 * @cfg {String} labelAlign top | left (default top)
6541 * @cfg {String} align left | right - for navbars
6542 * @cfg {Boolean} loadMask load mask when submit (default true)
6547 * @param {Object} config The config object
6551 Roo.bootstrap.Form = function(config){
6552 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6555 * @event clientvalidation
6556 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6557 * @param {Form} this
6558 * @param {Boolean} valid true if the form has passed client-side validation
6560 clientvalidation: true,
6562 * @event beforeaction
6563 * Fires before any action is performed. Return false to cancel the action.
6564 * @param {Form} this
6565 * @param {Action} action The action to be performed
6569 * @event actionfailed
6570 * Fires when an action fails.
6571 * @param {Form} this
6572 * @param {Action} action The action that failed
6574 actionfailed : true,
6576 * @event actioncomplete
6577 * Fires when an action is completed.
6578 * @param {Form} this
6579 * @param {Action} action The action that completed
6581 actioncomplete : true
6586 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6589 * @cfg {String} method
6590 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6595 * The URL to use for form actions if one isn't supplied in the action options.
6598 * @cfg {Boolean} fileUpload
6599 * Set to true if this form is a file upload.
6603 * @cfg {Object} baseParams
6604 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6608 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6612 * @cfg {Sting} align (left|right) for navbar forms
6617 activeAction : null,
6620 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6621 * element by passing it or its id or mask the form itself by passing in true.
6624 waitMsgTarget : false,
6628 getAutoCreate : function(){
6632 method : this.method || 'POST',
6633 id : this.id || Roo.id(),
6636 if (this.parent().xtype.match(/^Nav/)) {
6637 cfg.cls = 'navbar-form navbar-' + this.align;
6641 if (this.labelAlign == 'left' ) {
6642 cfg.cls += ' form-horizontal';
6648 initEvents : function()
6650 this.el.on('submit', this.onSubmit, this);
6651 // this was added as random key presses on the form where triggering form submit.
6652 this.el.on('keypress', function(e) {
6653 if (e.getCharCode() != 13) {
6656 // we might need to allow it for textareas.. and some other items.
6657 // check e.getTarget().
6659 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6663 Roo.log("keypress blocked");
6671 onSubmit : function(e){
6676 * Returns true if client-side validation on the form is successful.
6679 isValid : function(){
6680 var items = this.getItems();
6682 items.each(function(f){
6691 * Returns true if any fields in this form have changed since their original load.
6694 isDirty : function(){
6696 var items = this.getItems();
6697 items.each(function(f){
6707 * Performs a predefined action (submit or load) or custom actions you define on this form.
6708 * @param {String} actionName The name of the action type
6709 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6710 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6711 * accept other config options):
6713 Property Type Description
6714 ---------------- --------------- ----------------------------------------------------------------------------------
6715 url String The url for the action (defaults to the form's url)
6716 method String The form method to use (defaults to the form's method, or POST if not defined)
6717 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6718 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6719 validate the form on the client (defaults to false)
6721 * @return {BasicForm} this
6723 doAction : function(action, options){
6724 if(typeof action == 'string'){
6725 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6727 if(this.fireEvent('beforeaction', this, action) !== false){
6728 this.beforeAction(action);
6729 action.run.defer(100, action);
6735 beforeAction : function(action){
6736 var o = action.options;
6739 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6741 // not really supported yet.. ??
6743 //if(this.waitMsgTarget === true){
6744 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6745 //}else if(this.waitMsgTarget){
6746 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6747 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6749 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6755 afterAction : function(action, success){
6756 this.activeAction = null;
6757 var o = action.options;
6759 //if(this.waitMsgTarget === true){
6761 //}else if(this.waitMsgTarget){
6762 // this.waitMsgTarget.unmask();
6764 // Roo.MessageBox.updateProgress(1);
6765 // Roo.MessageBox.hide();
6772 Roo.callback(o.success, o.scope, [this, action]);
6773 this.fireEvent('actioncomplete', this, action);
6777 // failure condition..
6778 // we have a scenario where updates need confirming.
6779 // eg. if a locking scenario exists..
6780 // we look for { errors : { needs_confirm : true }} in the response.
6782 (typeof(action.result) != 'undefined') &&
6783 (typeof(action.result.errors) != 'undefined') &&
6784 (typeof(action.result.errors.needs_confirm) != 'undefined')
6787 Roo.log("not supported yet");
6790 Roo.MessageBox.confirm(
6791 "Change requires confirmation",
6792 action.result.errorMsg,
6797 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6807 Roo.callback(o.failure, o.scope, [this, action]);
6808 // show an error message if no failed handler is set..
6809 if (!this.hasListener('actionfailed')) {
6810 Roo.log("need to add dialog support");
6812 Roo.MessageBox.alert("Error",
6813 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6814 action.result.errorMsg :
6815 "Saving Failed, please check your entries or try again"
6820 this.fireEvent('actionfailed', this, action);
6825 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6826 * @param {String} id The value to search for
6829 findField : function(id){
6830 var items = this.getItems();
6831 var field = items.get(id);
6833 items.each(function(f){
6834 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6841 return field || null;
6844 * Mark fields in this form invalid in bulk.
6845 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6846 * @return {BasicForm} this
6848 markInvalid : function(errors){
6849 if(errors instanceof Array){
6850 for(var i = 0, len = errors.length; i < len; i++){
6851 var fieldError = errors[i];
6852 var f = this.findField(fieldError.id);
6854 f.markInvalid(fieldError.msg);
6860 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6861 field.markInvalid(errors[id]);
6865 //Roo.each(this.childForms || [], function (f) {
6866 // f.markInvalid(errors);
6873 * Set values for fields in this form in bulk.
6874 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6875 * @return {BasicForm} this
6877 setValues : function(values){
6878 if(values instanceof Array){ // array of objects
6879 for(var i = 0, len = values.length; i < len; i++){
6881 var f = this.findField(v.id);
6883 f.setValue(v.value);
6884 if(this.trackResetOnLoad){
6885 f.originalValue = f.getValue();
6889 }else{ // object hash
6892 if(typeof values[id] != 'function' && (field = this.findField(id))){
6894 if (field.setFromData &&
6896 field.displayField &&
6897 // combos' with local stores can
6898 // be queried via setValue()
6899 // to set their value..
6900 (field.store && !field.store.isLocal)
6904 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6905 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6906 field.setFromData(sd);
6909 field.setValue(values[id]);
6913 if(this.trackResetOnLoad){
6914 field.originalValue = field.getValue();
6920 //Roo.each(this.childForms || [], function (f) {
6921 // f.setValues(values);
6928 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6929 * they are returned as an array.
6930 * @param {Boolean} asString
6933 getValues : function(asString){
6934 //if (this.childForms) {
6935 // copy values from the child forms
6936 // Roo.each(this.childForms, function (f) {
6937 // this.setValues(f.getValues());
6943 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6944 if(asString === true){
6947 return Roo.urlDecode(fs);
6951 * Returns the fields in this form as an object with key/value pairs.
6952 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6955 getFieldValues : function(with_hidden)
6957 var items = this.getItems();
6959 items.each(function(f){
6963 var v = f.getValue();
6964 if (f.inputType =='radio') {
6965 if (typeof(ret[f.getName()]) == 'undefined') {
6966 ret[f.getName()] = ''; // empty..
6969 if (!f.el.dom.checked) {
6977 // not sure if this supported any more..
6978 if ((typeof(v) == 'object') && f.getRawValue) {
6979 v = f.getRawValue() ; // dates..
6981 // combo boxes where name != hiddenName...
6982 if (f.name != f.getName()) {
6983 ret[f.name] = f.getRawValue();
6985 ret[f.getName()] = v;
6992 * Clears all invalid messages in this form.
6993 * @return {BasicForm} this
6995 clearInvalid : function(){
6996 var items = this.getItems();
6998 items.each(function(f){
7009 * @return {BasicForm} this
7012 var items = this.getItems();
7013 items.each(function(f){
7017 Roo.each(this.childForms || [], function (f) {
7024 getItems : function()
7026 var r=new Roo.util.MixedCollection(false, function(o){
7027 return o.id || (o.id = Roo.id());
7029 var iter = function(el) {
7036 Roo.each(el.items,function(e) {
7056 * Ext JS Library 1.1.1
7057 * Copyright(c) 2006-2007, Ext JS, LLC.
7059 * Originally Released Under LGPL - original licence link has changed is not relivant.
7062 * <script type="text/javascript">
7065 * @class Roo.form.VTypes
7066 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7069 Roo.form.VTypes = function(){
7070 // closure these in so they are only created once.
7071 var alpha = /^[a-zA-Z_]+$/;
7072 var alphanum = /^[a-zA-Z0-9_]+$/;
7073 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7074 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7076 // All these messages and functions are configurable
7079 * The function used to validate email addresses
7080 * @param {String} value The email address
7082 'email' : function(v){
7083 return email.test(v);
7086 * The error text to display when the email validation function returns false
7089 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7091 * The keystroke filter mask to be applied on email input
7094 'emailMask' : /[a-z0-9_\.\-@]/i,
7097 * The function used to validate URLs
7098 * @param {String} value The URL
7100 'url' : function(v){
7104 * The error text to display when the url validation function returns false
7107 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7110 * The function used to validate alpha values
7111 * @param {String} value The value
7113 'alpha' : function(v){
7114 return alpha.test(v);
7117 * The error text to display when the alpha validation function returns false
7120 'alphaText' : 'This field should only contain letters and _',
7122 * The keystroke filter mask to be applied on alpha input
7125 'alphaMask' : /[a-z_]/i,
7128 * The function used to validate alphanumeric values
7129 * @param {String} value The value
7131 'alphanum' : function(v){
7132 return alphanum.test(v);
7135 * The error text to display when the alphanumeric validation function returns false
7138 'alphanumText' : 'This field should only contain letters, numbers and _',
7140 * The keystroke filter mask to be applied on alphanumeric input
7143 'alphanumMask' : /[a-z0-9_]/i
7153 * @class Roo.bootstrap.Input
7154 * @extends Roo.bootstrap.Component
7155 * Bootstrap Input class
7156 * @cfg {Boolean} disabled is it disabled
7157 * @cfg {String} fieldLabel - the label associated
7158 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7159 * @cfg {String} name name of the input
7160 * @cfg {string} fieldLabel - the label associated
7161 * @cfg {string} inputType - input / file submit ...
7162 * @cfg {string} placeholder - placeholder to put in text.
7163 * @cfg {string} before - input group add on before
7164 * @cfg {string} after - input group add on after
7165 * @cfg {string} size - (lg|sm) or leave empty..
7166 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7167 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7168 * @cfg {Number} md colspan out of 12 for computer-sized screens
7169 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7170 * @cfg {string} value default value of the input
7171 * @cfg {Number} labelWidth set the width of label (0-12)
7172 * @cfg {String} labelAlign (top|left)
7173 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7174 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7176 * @cfg {String} align (left|center|right) Default left
7181 * Create a new Input
7182 * @param {Object} config The config object
7185 Roo.bootstrap.Input = function(config){
7186 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7191 * Fires when this field receives input focus.
7192 * @param {Roo.form.Field} this
7197 * Fires when this field loses input focus.
7198 * @param {Roo.form.Field} this
7203 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7204 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7205 * @param {Roo.form.Field} this
7206 * @param {Roo.EventObject} e The event object
7211 * Fires just before the field blurs if the field value has changed.
7212 * @param {Roo.form.Field} this
7213 * @param {Mixed} newValue The new value
7214 * @param {Mixed} oldValue The original value
7219 * Fires after the field has been marked as invalid.
7220 * @param {Roo.form.Field} this
7221 * @param {String} msg The validation message
7226 * Fires after the field has been validated with no errors.
7227 * @param {Roo.form.Field} this
7232 * Fires after the key up
7233 * @param {Roo.form.Field} this
7234 * @param {Roo.EventObject} e The event Object
7240 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7242 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7243 automatic validation (defaults to "keyup").
7245 validationEvent : "keyup",
7247 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7249 validateOnBlur : true,
7251 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7253 validationDelay : 250,
7255 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7257 focusClass : "x-form-focus", // not needed???
7261 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7263 invalidClass : "has-warning",
7266 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7268 validClass : "has-success",
7271 * @cfg {Boolean} hasFeedback (true|false) default true
7276 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7278 invalidFeedbackClass : "glyphicon-warning-sign",
7281 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7283 validFeedbackClass : "glyphicon-ok",
7286 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7288 selectOnFocus : false,
7291 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7295 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7300 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7302 disableKeyFilter : false,
7305 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7309 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7313 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7315 blankText : "This field is required",
7318 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7322 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7324 maxLength : Number.MAX_VALUE,
7326 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7328 minLengthText : "The minimum length for this field is {0}",
7330 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7332 maxLengthText : "The maximum length for this field is {0}",
7336 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7337 * If available, this function will be called only after the basic validators all return true, and will be passed the
7338 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7342 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7343 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7344 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7348 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7352 autocomplete: false,
7371 formatedValue : false,
7373 parentLabelAlign : function()
7376 while (parent.parent()) {
7377 parent = parent.parent();
7378 if (typeof(parent.labelAlign) !='undefined') {
7379 return parent.labelAlign;
7386 getAutoCreate : function(){
7388 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7394 if(this.inputType != 'hidden'){
7395 cfg.cls = 'form-group' //input-group
7401 type : this.inputType,
7403 cls : 'form-control',
7404 placeholder : this.placeholder || '',
7405 autocomplete : this.autocomplete || 'new-password'
7410 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7413 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7414 input.maxLength = this.maxLength;
7417 if (this.disabled) {
7418 input.disabled=true;
7421 if (this.readOnly) {
7422 input.readonly=true;
7426 input.name = this.name;
7429 input.cls += ' input-' + this.size;
7432 ['xs','sm','md','lg'].map(function(size){
7433 if (settings[size]) {
7434 cfg.cls += ' col-' + size + '-' + settings[size];
7438 var inputblock = input;
7440 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7444 cls: 'glyphicon form-control-feedback'
7448 cls : 'has-feedback',
7456 // var inputblock = input;
7458 if (this.before || this.after) {
7461 cls : 'input-group',
7465 if (this.before && typeof(this.before) == 'string') {
7467 inputblock.cn.push({
7469 cls : 'roo-input-before input-group-addon',
7473 if (this.before && typeof(this.before) == 'object') {
7474 this.before = Roo.factory(this.before);
7475 Roo.log(this.before);
7476 inputblock.cn.push({
7478 cls : 'roo-input-before input-group-' +
7479 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7483 inputblock.cn.push(input);
7485 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7486 inputblock.cls += ' has-feedback';
7487 inputblock.cn.push(feedback);
7490 if (this.after && typeof(this.after) == 'string') {
7491 inputblock.cn.push({
7493 cls : 'roo-input-after input-group-addon',
7497 if (this.after && typeof(this.after) == 'object') {
7498 this.after = Roo.factory(this.after);
7499 Roo.log(this.after);
7500 inputblock.cn.push({
7502 cls : 'roo-input-after input-group-' +
7503 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7508 if (align ==='left' && this.fieldLabel.length) {
7509 Roo.log("left and has label");
7515 cls : 'control-label col-sm-' + this.labelWidth,
7516 html : this.fieldLabel
7520 cls : "col-sm-" + (12 - this.labelWidth),
7527 } else if ( this.fieldLabel.length) {
7533 //cls : 'input-group-addon',
7534 html : this.fieldLabel
7544 Roo.log(" no label && no align");
7553 Roo.log('input-parentType: ' + this.parentType);
7555 if (this.parentType === 'Navbar' && this.parent().bar) {
7556 cfg.cls += ' navbar-form';
7564 * return the real input element.
7566 inputEl: function ()
7568 return this.el.select('input.form-control',true).first();
7571 tooltipEl : function()
7573 return this.inputEl();
7576 setDisabled : function(v)
7578 var i = this.inputEl().dom;
7580 i.removeAttribute('disabled');
7584 i.setAttribute('disabled','true');
7586 initEvents : function()
7589 this.inputEl().on("keydown" , this.fireKey, this);
7590 this.inputEl().on("focus", this.onFocus, this);
7591 this.inputEl().on("blur", this.onBlur, this);
7593 this.inputEl().relayEvent('keyup', this);
7595 // reference to original value for reset
7596 this.originalValue = this.getValue();
7597 //Roo.form.TextField.superclass.initEvents.call(this);
7598 if(this.validationEvent == 'keyup'){
7599 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7600 this.inputEl().on('keyup', this.filterValidation, this);
7602 else if(this.validationEvent !== false){
7603 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7606 if(this.selectOnFocus){
7607 this.on("focus", this.preFocus, this);
7610 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7611 this.inputEl().on("keypress", this.filterKeys, this);
7614 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7615 this.el.on("click", this.autoSize, this);
7618 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7619 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7622 if (typeof(this.before) == 'object') {
7623 this.before.render(this.el.select('.roo-input-before',true).first());
7625 if (typeof(this.after) == 'object') {
7626 this.after.render(this.el.select('.roo-input-after',true).first());
7631 filterValidation : function(e){
7632 if(!e.isNavKeyPress()){
7633 this.validationTask.delay(this.validationDelay);
7637 * Validates the field value
7638 * @return {Boolean} True if the value is valid, else false
7640 validate : function(){
7641 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7642 if(this.disabled || this.validateValue(this.getRawValue())){
7653 * Validates a value according to the field's validation rules and marks the field as invalid
7654 * if the validation fails
7655 * @param {Mixed} value The value to validate
7656 * @return {Boolean} True if the value is valid, else false
7658 validateValue : function(value){
7659 if(value.length < 1) { // if it's blank
7660 if(this.allowBlank){
7666 if(value.length < this.minLength){
7669 if(value.length > this.maxLength){
7673 var vt = Roo.form.VTypes;
7674 if(!vt[this.vtype](value, this)){
7678 if(typeof this.validator == "function"){
7679 var msg = this.validator(value);
7685 if(this.regex && !this.regex.test(value)){
7695 fireKey : function(e){
7696 //Roo.log('field ' + e.getKey());
7697 if(e.isNavKeyPress()){
7698 this.fireEvent("specialkey", this, e);
7701 focus : function (selectText){
7703 this.inputEl().focus();
7704 if(selectText === true){
7705 this.inputEl().dom.select();
7711 onFocus : function(){
7712 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7713 // this.el.addClass(this.focusClass);
7716 this.hasFocus = true;
7717 this.startValue = this.getValue();
7718 this.fireEvent("focus", this);
7722 beforeBlur : Roo.emptyFn,
7726 onBlur : function(){
7728 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7729 //this.el.removeClass(this.focusClass);
7731 this.hasFocus = false;
7732 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7735 var v = this.getValue();
7736 if(String(v) !== String(this.startValue)){
7737 this.fireEvent('change', this, v, this.startValue);
7739 this.fireEvent("blur", this);
7743 * Resets the current field value to the originally loaded value and clears any validation messages
7746 this.setValue(this.originalValue);
7750 * Returns the name of the field
7751 * @return {Mixed} name The name field
7753 getName: function(){
7757 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7758 * @return {Mixed} value The field value
7760 getValue : function(){
7762 var v = this.inputEl().getValue();
7767 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7768 * @return {Mixed} value The field value
7770 getRawValue : function(){
7771 var v = this.inputEl().getValue();
7777 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7778 * @param {Mixed} value The value to set
7780 setRawValue : function(v){
7781 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7784 selectText : function(start, end){
7785 var v = this.getRawValue();
7787 start = start === undefined ? 0 : start;
7788 end = end === undefined ? v.length : end;
7789 var d = this.inputEl().dom;
7790 if(d.setSelectionRange){
7791 d.setSelectionRange(start, end);
7792 }else if(d.createTextRange){
7793 var range = d.createTextRange();
7794 range.moveStart("character", start);
7795 range.moveEnd("character", v.length-end);
7802 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7803 * @param {Mixed} value The value to set
7805 setValue : function(v){
7808 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7814 processValue : function(value){
7815 if(this.stripCharsRe){
7816 var newValue = value.replace(this.stripCharsRe, '');
7817 if(newValue !== value){
7818 this.setRawValue(newValue);
7825 preFocus : function(){
7827 if(this.selectOnFocus){
7828 this.inputEl().dom.select();
7831 filterKeys : function(e){
7833 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7836 var c = e.getCharCode(), cc = String.fromCharCode(c);
7837 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7840 if(!this.maskRe.test(cc)){
7845 * Clear any invalid styles/messages for this field
7847 clearInvalid : function(){
7849 if(!this.el || this.preventMark){ // not rendered
7852 this.el.removeClass(this.invalidClass);
7854 this.fireEvent('valid', this);
7858 * Mark this field as valid
7860 markValid : function(){
7861 if(!this.el || this.preventMark){ // not rendered
7865 this.el.removeClass([this.invalidClass, this.validClass]);
7867 if(this.disabled || this.allowBlank){
7871 this.el.addClass(this.validClass);
7873 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7875 var feedback = this.el.select('.form-control-feedback', true).first();
7878 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7879 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7884 this.fireEvent('valid', this);
7888 * Mark this field as invalid
7889 * @param {String} msg The validation message
7891 markInvalid : function(msg){
7892 if(!this.el || this.preventMark){ // not rendered
7896 this.el.removeClass([this.invalidClass, this.validClass]);
7898 if(this.disabled || this.allowBlank){
7902 this.el.addClass(this.invalidClass);
7904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7906 var feedback = this.el.select('.form-control-feedback', true).first();
7909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7911 if(this.getValue().length){
7912 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7919 this.fireEvent('invalid', this, msg);
7922 SafariOnKeyDown : function(event)
7924 // this is a workaround for a password hang bug on chrome/ webkit.
7926 var isSelectAll = false;
7928 if(this.inputEl().dom.selectionEnd > 0){
7929 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7931 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7932 event.preventDefault();
7937 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7939 event.preventDefault();
7940 // this is very hacky as keydown always get's upper case.
7942 var cc = String.fromCharCode(event.getCharCode());
7943 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7947 adjustWidth : function(tag, w){
7948 tag = tag.toLowerCase();
7949 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7950 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7954 if(tag == 'textarea'){
7957 }else if(Roo.isOpera){
7961 if(tag == 'textarea'){
7980 * @class Roo.bootstrap.TextArea
7981 * @extends Roo.bootstrap.Input
7982 * Bootstrap TextArea class
7983 * @cfg {Number} cols Specifies the visible width of a text area
7984 * @cfg {Number} rows Specifies the visible number of lines in a text area
7985 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7986 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7987 * @cfg {string} html text
7990 * Create a new TextArea
7991 * @param {Object} config The config object
7994 Roo.bootstrap.TextArea = function(config){
7995 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7999 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8009 getAutoCreate : function(){
8011 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8022 value : this.value || '',
8023 html: this.html || '',
8024 cls : 'form-control',
8025 placeholder : this.placeholder || ''
8029 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8030 input.maxLength = this.maxLength;
8034 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8038 input.cols = this.cols;
8041 if (this.readOnly) {
8042 input.readonly = true;
8046 input.name = this.name;
8050 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8054 ['xs','sm','md','lg'].map(function(size){
8055 if (settings[size]) {
8056 cfg.cls += ' col-' + size + '-' + settings[size];
8060 var inputblock = input;
8062 if(this.hasFeedback && !this.allowBlank){
8066 cls: 'glyphicon form-control-feedback'
8070 cls : 'has-feedback',
8079 if (this.before || this.after) {
8082 cls : 'input-group',
8086 inputblock.cn.push({
8088 cls : 'input-group-addon',
8093 inputblock.cn.push(input);
8095 if(this.hasFeedback && !this.allowBlank){
8096 inputblock.cls += ' has-feedback';
8097 inputblock.cn.push(feedback);
8101 inputblock.cn.push({
8103 cls : 'input-group-addon',
8110 if (align ==='left' && this.fieldLabel.length) {
8111 Roo.log("left and has label");
8117 cls : 'control-label col-sm-' + this.labelWidth,
8118 html : this.fieldLabel
8122 cls : "col-sm-" + (12 - this.labelWidth),
8129 } else if ( this.fieldLabel.length) {
8135 //cls : 'input-group-addon',
8136 html : this.fieldLabel
8146 Roo.log(" no label && no align");
8156 if (this.disabled) {
8157 input.disabled=true;
8164 * return the real textarea element.
8166 inputEl: function ()
8168 return this.el.select('textarea.form-control',true).first();
8176 * trigger field - base class for combo..
8181 * @class Roo.bootstrap.TriggerField
8182 * @extends Roo.bootstrap.Input
8183 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8184 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8185 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8186 * for which you can provide a custom implementation. For example:
8188 var trigger = new Roo.bootstrap.TriggerField();
8189 trigger.onTriggerClick = myTriggerFn;
8190 trigger.applyTo('my-field');
8193 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8194 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8195 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8196 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8197 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8200 * Create a new TriggerField.
8201 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8202 * to the base TextField)
8204 Roo.bootstrap.TriggerField = function(config){
8205 this.mimicing = false;
8206 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8209 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8211 * @cfg {String} triggerClass A CSS class to apply to the trigger
8214 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8218 /** @cfg {Boolean} grow @hide */
8219 /** @cfg {Number} growMin @hide */
8220 /** @cfg {Number} growMax @hide */
8226 autoSize: Roo.emptyFn,
8233 actionMode : 'wrap',
8238 getAutoCreate : function(){
8240 var align = this.labelAlign || this.parentLabelAlign();
8245 cls: 'form-group' //input-group
8252 type : this.inputType,
8253 cls : 'form-control',
8254 autocomplete: 'new-password',
8255 placeholder : this.placeholder || ''
8259 input.name = this.name;
8262 input.cls += ' input-' + this.size;
8265 if (this.disabled) {
8266 input.disabled=true;
8269 var inputblock = input;
8271 if(this.hasFeedback && !this.allowBlank){
8275 cls: 'glyphicon form-control-feedback'
8279 cls : 'has-feedback',
8287 if (this.before || this.after) {
8290 cls : 'input-group',
8294 inputblock.cn.push({
8296 cls : 'input-group-addon',
8301 inputblock.cn.push(input);
8303 if(this.hasFeedback && !this.allowBlank){
8304 inputblock.cls += ' has-feedback';
8305 inputblock.cn.push(feedback);
8309 inputblock.cn.push({
8311 cls : 'input-group-addon',
8324 cls: 'form-hidden-field'
8332 Roo.log('multiple');
8340 cls: 'form-hidden-field'
8344 cls: 'select2-choices',
8348 cls: 'select2-search-field',
8361 cls: 'select2-container input-group',
8366 // cls: 'typeahead typeahead-long dropdown-menu',
8367 // style: 'display:none'
8372 if(!this.multiple && this.showToggleBtn){
8378 if (this.caret != false) {
8381 cls: 'fa fa-' + this.caret
8388 cls : 'input-group-addon btn dropdown-toggle',
8393 cls: 'combobox-clear',
8407 combobox.cls += ' select2-container-multi';
8410 if (align ==='left' && this.fieldLabel.length) {
8412 Roo.log("left and has label");
8418 cls : 'control-label col-sm-' + this.labelWidth,
8419 html : this.fieldLabel
8423 cls : "col-sm-" + (12 - this.labelWidth),
8430 } else if ( this.fieldLabel.length) {
8436 //cls : 'input-group-addon',
8437 html : this.fieldLabel
8447 Roo.log(" no label && no align");
8454 ['xs','sm','md','lg'].map(function(size){
8455 if (settings[size]) {
8456 cfg.cls += ' col-' + size + '-' + settings[size];
8467 onResize : function(w, h){
8468 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8469 // if(typeof w == 'number'){
8470 // var x = w - this.trigger.getWidth();
8471 // this.inputEl().setWidth(this.adjustWidth('input', x));
8472 // this.trigger.setStyle('left', x+'px');
8477 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8480 getResizeEl : function(){
8481 return this.inputEl();
8485 getPositionEl : function(){
8486 return this.inputEl();
8490 alignErrorIcon : function(){
8491 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8495 initEvents : function(){
8499 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8500 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8501 if(!this.multiple && this.showToggleBtn){
8502 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8503 if(this.hideTrigger){
8504 this.trigger.setDisplayed(false);
8506 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8510 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8513 //this.trigger.addClassOnOver('x-form-trigger-over');
8514 //this.trigger.addClassOnClick('x-form-trigger-click');
8517 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8521 createList : function()
8523 this.list = Roo.get(document.body).createChild({
8525 cls: 'typeahead typeahead-long dropdown-menu',
8526 style: 'display:none'
8529 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8534 initTrigger : function(){
8539 onDestroy : function(){
8541 this.trigger.removeAllListeners();
8542 // this.trigger.remove();
8545 // this.wrap.remove();
8547 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8551 onFocus : function(){
8552 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8555 this.wrap.addClass('x-trigger-wrap-focus');
8556 this.mimicing = true;
8557 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8558 if(this.monitorTab){
8559 this.el.on("keydown", this.checkTab, this);
8566 checkTab : function(e){
8567 if(e.getKey() == e.TAB){
8573 onBlur : function(){
8578 mimicBlur : function(e, t){
8580 if(!this.wrap.contains(t) && this.validateBlur()){
8587 triggerBlur : function(){
8588 this.mimicing = false;
8589 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8590 if(this.monitorTab){
8591 this.el.un("keydown", this.checkTab, this);
8593 //this.wrap.removeClass('x-trigger-wrap-focus');
8594 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8598 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8599 validateBlur : function(e, t){
8604 onDisable : function(){
8605 this.inputEl().dom.disabled = true;
8606 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8608 // this.wrap.addClass('x-item-disabled');
8613 onEnable : function(){
8614 this.inputEl().dom.disabled = false;
8615 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8617 // this.el.removeClass('x-item-disabled');
8622 onShow : function(){
8623 var ae = this.getActionEl();
8626 ae.dom.style.display = '';
8627 ae.dom.style.visibility = 'visible';
8633 onHide : function(){
8634 var ae = this.getActionEl();
8635 ae.dom.style.display = 'none';
8639 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8640 * by an implementing function.
8642 * @param {EventObject} e
8644 onTriggerClick : Roo.emptyFn
8648 * Ext JS Library 1.1.1
8649 * Copyright(c) 2006-2007, Ext JS, LLC.
8651 * Originally Released Under LGPL - original licence link has changed is not relivant.
8654 * <script type="text/javascript">
8659 * @class Roo.data.SortTypes
8661 * Defines the default sorting (casting?) comparison functions used when sorting data.
8663 Roo.data.SortTypes = {
8665 * Default sort that does nothing
8666 * @param {Mixed} s The value being converted
8667 * @return {Mixed} The comparison value
8674 * The regular expression used to strip tags
8678 stripTagsRE : /<\/?[^>]+>/gi,
8681 * Strips all HTML tags to sort on text only
8682 * @param {Mixed} s The value being converted
8683 * @return {String} The comparison value
8685 asText : function(s){
8686 return String(s).replace(this.stripTagsRE, "");
8690 * Strips all HTML tags to sort on text only - Case insensitive
8691 * @param {Mixed} s The value being converted
8692 * @return {String} The comparison value
8694 asUCText : function(s){
8695 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8699 * Case insensitive string
8700 * @param {Mixed} s The value being converted
8701 * @return {String} The comparison value
8703 asUCString : function(s) {
8704 return String(s).toUpperCase();
8709 * @param {Mixed} s The value being converted
8710 * @return {Number} The comparison value
8712 asDate : function(s) {
8716 if(s instanceof Date){
8719 return Date.parse(String(s));
8724 * @param {Mixed} s The value being converted
8725 * @return {Float} The comparison value
8727 asFloat : function(s) {
8728 var val = parseFloat(String(s).replace(/,/g, ""));
8729 if(isNaN(val)) val = 0;
8735 * @param {Mixed} s The value being converted
8736 * @return {Number} The comparison value
8738 asInt : function(s) {
8739 var val = parseInt(String(s).replace(/,/g, ""));
8740 if(isNaN(val)) val = 0;
8745 * Ext JS Library 1.1.1
8746 * Copyright(c) 2006-2007, Ext JS, LLC.
8748 * Originally Released Under LGPL - original licence link has changed is not relivant.
8751 * <script type="text/javascript">
8755 * @class Roo.data.Record
8756 * Instances of this class encapsulate both record <em>definition</em> information, and record
8757 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8758 * to access Records cached in an {@link Roo.data.Store} object.<br>
8760 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8761 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8764 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8766 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8767 * {@link #create}. The parameters are the same.
8768 * @param {Array} data An associative Array of data values keyed by the field name.
8769 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8770 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8771 * not specified an integer id is generated.
8773 Roo.data.Record = function(data, id){
8774 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8779 * Generate a constructor for a specific record layout.
8780 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8781 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8782 * Each field definition object may contain the following properties: <ul>
8783 * <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,
8784 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8785 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8786 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8787 * is being used, then this is a string containing the javascript expression to reference the data relative to
8788 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8789 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8790 * this may be omitted.</p></li>
8791 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8792 * <ul><li>auto (Default, implies no conversion)</li>
8797 * <li>date</li></ul></p></li>
8798 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8799 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8800 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8801 * by the Reader into an object that will be stored in the Record. It is passed the
8802 * following parameters:<ul>
8803 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8805 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8807 * <br>usage:<br><pre><code>
8808 var TopicRecord = Roo.data.Record.create(
8809 {name: 'title', mapping: 'topic_title'},
8810 {name: 'author', mapping: 'username'},
8811 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8812 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8813 {name: 'lastPoster', mapping: 'user2'},
8814 {name: 'excerpt', mapping: 'post_text'}
8817 var myNewRecord = new TopicRecord({
8818 title: 'Do my job please',
8821 lastPost: new Date(),
8822 lastPoster: 'Animal',
8823 excerpt: 'No way dude!'
8825 myStore.add(myNewRecord);
8830 Roo.data.Record.create = function(o){
8832 f.superclass.constructor.apply(this, arguments);
8834 Roo.extend(f, Roo.data.Record);
8835 var p = f.prototype;
8836 p.fields = new Roo.util.MixedCollection(false, function(field){
8839 for(var i = 0, len = o.length; i < len; i++){
8840 p.fields.add(new Roo.data.Field(o[i]));
8842 f.getField = function(name){
8843 return p.fields.get(name);
8848 Roo.data.Record.AUTO_ID = 1000;
8849 Roo.data.Record.EDIT = 'edit';
8850 Roo.data.Record.REJECT = 'reject';
8851 Roo.data.Record.COMMIT = 'commit';
8853 Roo.data.Record.prototype = {
8855 * Readonly flag - true if this record has been modified.
8864 join : function(store){
8869 * Set the named field to the specified value.
8870 * @param {String} name The name of the field to set.
8871 * @param {Object} value The value to set the field to.
8873 set : function(name, value){
8874 if(this.data[name] == value){
8881 if(typeof this.modified[name] == 'undefined'){
8882 this.modified[name] = this.data[name];
8884 this.data[name] = value;
8885 if(!this.editing && this.store){
8886 this.store.afterEdit(this);
8891 * Get the value of the named field.
8892 * @param {String} name The name of the field to get the value of.
8893 * @return {Object} The value of the field.
8895 get : function(name){
8896 return this.data[name];
8900 beginEdit : function(){
8901 this.editing = true;
8906 cancelEdit : function(){
8907 this.editing = false;
8908 delete this.modified;
8912 endEdit : function(){
8913 this.editing = false;
8914 if(this.dirty && this.store){
8915 this.store.afterEdit(this);
8920 * Usually called by the {@link Roo.data.Store} which owns the Record.
8921 * Rejects all changes made to the Record since either creation, or the last commit operation.
8922 * Modified fields are reverted to their original values.
8924 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8925 * of reject operations.
8927 reject : function(){
8928 var m = this.modified;
8930 if(typeof m[n] != "function"){
8931 this.data[n] = m[n];
8935 delete this.modified;
8936 this.editing = false;
8938 this.store.afterReject(this);
8943 * Usually called by the {@link Roo.data.Store} which owns the Record.
8944 * Commits all changes made to the Record since either creation, or the last commit operation.
8946 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8947 * of commit operations.
8949 commit : function(){
8951 delete this.modified;
8952 this.editing = false;
8954 this.store.afterCommit(this);
8959 hasError : function(){
8960 return this.error != null;
8964 clearError : function(){
8969 * Creates a copy of this record.
8970 * @param {String} id (optional) A new record id if you don't want to use this record's id
8973 copy : function(newId) {
8974 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8978 * Ext JS Library 1.1.1
8979 * Copyright(c) 2006-2007, Ext JS, LLC.
8981 * Originally Released Under LGPL - original licence link has changed is not relivant.
8984 * <script type="text/javascript">
8990 * @class Roo.data.Store
8991 * @extends Roo.util.Observable
8992 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8993 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8995 * 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
8996 * has no knowledge of the format of the data returned by the Proxy.<br>
8998 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8999 * instances from the data object. These records are cached and made available through accessor functions.
9001 * Creates a new Store.
9002 * @param {Object} config A config object containing the objects needed for the Store to access data,
9003 * and read the data into Records.
9005 Roo.data.Store = function(config){
9006 this.data = new Roo.util.MixedCollection(false);
9007 this.data.getKey = function(o){
9010 this.baseParams = {};
9017 "multisort" : "_multisort"
9020 if(config && config.data){
9021 this.inlineData = config.data;
9025 Roo.apply(this, config);
9027 if(this.reader){ // reader passed
9028 this.reader = Roo.factory(this.reader, Roo.data);
9029 this.reader.xmodule = this.xmodule || false;
9030 if(!this.recordType){
9031 this.recordType = this.reader.recordType;
9033 if(this.reader.onMetaChange){
9034 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9038 if(this.recordType){
9039 this.fields = this.recordType.prototype.fields;
9045 * @event datachanged
9046 * Fires when the data cache has changed, and a widget which is using this Store
9047 * as a Record cache should refresh its view.
9048 * @param {Store} this
9053 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9054 * @param {Store} this
9055 * @param {Object} meta The JSON metadata
9060 * Fires when Records have been added to the Store
9061 * @param {Store} this
9062 * @param {Roo.data.Record[]} records The array of Records added
9063 * @param {Number} index The index at which the record(s) were added
9068 * Fires when a Record has been removed from the Store
9069 * @param {Store} this
9070 * @param {Roo.data.Record} record The Record that was removed
9071 * @param {Number} index The index at which the record was removed
9076 * Fires when a Record has been updated
9077 * @param {Store} this
9078 * @param {Roo.data.Record} record The Record that was updated
9079 * @param {String} operation The update operation being performed. Value may be one of:
9081 Roo.data.Record.EDIT
9082 Roo.data.Record.REJECT
9083 Roo.data.Record.COMMIT
9089 * Fires when the data cache has been cleared.
9090 * @param {Store} this
9095 * Fires before a request is made for a new data object. If the beforeload handler returns false
9096 * the load action will be canceled.
9097 * @param {Store} this
9098 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9102 * @event beforeloadadd
9103 * Fires after a new set of Records has been loaded.
9104 * @param {Store} this
9105 * @param {Roo.data.Record[]} records The Records that were loaded
9106 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9108 beforeloadadd : true,
9111 * Fires after a new set of Records has been loaded, before they are added to the store.
9112 * @param {Store} this
9113 * @param {Roo.data.Record[]} records The Records that were loaded
9114 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9115 * @params {Object} return from reader
9119 * @event loadexception
9120 * Fires if an exception occurs in the Proxy during loading.
9121 * Called with the signature of the Proxy's "loadexception" event.
9122 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9125 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9126 * @param {Object} load options
9127 * @param {Object} jsonData from your request (normally this contains the Exception)
9129 loadexception : true
9133 this.proxy = Roo.factory(this.proxy, Roo.data);
9134 this.proxy.xmodule = this.xmodule || false;
9135 this.relayEvents(this.proxy, ["loadexception"]);
9137 this.sortToggle = {};
9138 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9140 Roo.data.Store.superclass.constructor.call(this);
9142 if(this.inlineData){
9143 this.loadData(this.inlineData);
9144 delete this.inlineData;
9148 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9150 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9151 * without a remote query - used by combo/forms at present.
9155 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9158 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9161 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9162 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9165 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9166 * on any HTTP request
9169 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9172 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9176 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9177 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9182 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9183 * loaded or when a record is removed. (defaults to false).
9185 pruneModifiedRecords : false,
9191 * Add Records to the Store and fires the add event.
9192 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9194 add : function(records){
9195 records = [].concat(records);
9196 for(var i = 0, len = records.length; i < len; i++){
9197 records[i].join(this);
9199 var index = this.data.length;
9200 this.data.addAll(records);
9201 this.fireEvent("add", this, records, index);
9205 * Remove a Record from the Store and fires the remove event.
9206 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9208 remove : function(record){
9209 var index = this.data.indexOf(record);
9210 this.data.removeAt(index);
9211 if(this.pruneModifiedRecords){
9212 this.modified.remove(record);
9214 this.fireEvent("remove", this, record, index);
9218 * Remove all Records from the Store and fires the clear event.
9220 removeAll : function(){
9222 if(this.pruneModifiedRecords){
9225 this.fireEvent("clear", this);
9229 * Inserts Records to the Store at the given index and fires the add event.
9230 * @param {Number} index The start index at which to insert the passed Records.
9231 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9233 insert : function(index, records){
9234 records = [].concat(records);
9235 for(var i = 0, len = records.length; i < len; i++){
9236 this.data.insert(index, records[i]);
9237 records[i].join(this);
9239 this.fireEvent("add", this, records, index);
9243 * Get the index within the cache of the passed Record.
9244 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9245 * @return {Number} The index of the passed Record. Returns -1 if not found.
9247 indexOf : function(record){
9248 return this.data.indexOf(record);
9252 * Get the index within the cache of the Record with the passed id.
9253 * @param {String} id The id of the Record to find.
9254 * @return {Number} The index of the Record. Returns -1 if not found.
9256 indexOfId : function(id){
9257 return this.data.indexOfKey(id);
9261 * Get the Record with the specified id.
9262 * @param {String} id The id of the Record to find.
9263 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9265 getById : function(id){
9266 return this.data.key(id);
9270 * Get the Record at the specified index.
9271 * @param {Number} index The index of the Record to find.
9272 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9274 getAt : function(index){
9275 return this.data.itemAt(index);
9279 * Returns a range of Records between specified indices.
9280 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9281 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9282 * @return {Roo.data.Record[]} An array of Records
9284 getRange : function(start, end){
9285 return this.data.getRange(start, end);
9289 storeOptions : function(o){
9290 o = Roo.apply({}, o);
9293 this.lastOptions = o;
9297 * Loads the Record cache from the configured Proxy using the configured Reader.
9299 * If using remote paging, then the first load call must specify the <em>start</em>
9300 * and <em>limit</em> properties in the options.params property to establish the initial
9301 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9303 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9304 * and this call will return before the new data has been loaded. Perform any post-processing
9305 * in a callback function, or in a "load" event handler.</strong>
9307 * @param {Object} options An object containing properties which control loading options:<ul>
9308 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9309 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9310 * passed the following arguments:<ul>
9311 * <li>r : Roo.data.Record[]</li>
9312 * <li>options: Options object from the load call</li>
9313 * <li>success: Boolean success indicator</li></ul></li>
9314 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9315 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9318 load : function(options){
9319 options = options || {};
9320 if(this.fireEvent("beforeload", this, options) !== false){
9321 this.storeOptions(options);
9322 var p = Roo.apply(options.params || {}, this.baseParams);
9323 // if meta was not loaded from remote source.. try requesting it.
9324 if (!this.reader.metaFromRemote) {
9327 if(this.sortInfo && this.remoteSort){
9328 var pn = this.paramNames;
9329 p[pn["sort"]] = this.sortInfo.field;
9330 p[pn["dir"]] = this.sortInfo.direction;
9332 if (this.multiSort) {
9333 var pn = this.paramNames;
9334 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9337 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9342 * Reloads the Record cache from the configured Proxy using the configured Reader and
9343 * the options from the last load operation performed.
9344 * @param {Object} options (optional) An object containing properties which may override the options
9345 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9346 * the most recently used options are reused).
9348 reload : function(options){
9349 this.load(Roo.applyIf(options||{}, this.lastOptions));
9353 // Called as a callback by the Reader during a load operation.
9354 loadRecords : function(o, options, success){
9355 if(!o || success === false){
9356 if(success !== false){
9357 this.fireEvent("load", this, [], options, o);
9359 if(options.callback){
9360 options.callback.call(options.scope || this, [], options, false);
9364 // if data returned failure - throw an exception.
9365 if (o.success === false) {
9366 // show a message if no listener is registered.
9367 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9368 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9370 // loadmask wil be hooked into this..
9371 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9374 var r = o.records, t = o.totalRecords || r.length;
9376 this.fireEvent("beforeloadadd", this, r, options, o);
9378 if(!options || options.add !== true){
9379 if(this.pruneModifiedRecords){
9382 for(var i = 0, len = r.length; i < len; i++){
9386 this.data = this.snapshot;
9387 delete this.snapshot;
9390 this.data.addAll(r);
9391 this.totalLength = t;
9393 this.fireEvent("datachanged", this);
9395 this.totalLength = Math.max(t, this.data.length+r.length);
9398 this.fireEvent("load", this, r, options, o);
9399 if(options.callback){
9400 options.callback.call(options.scope || this, r, options, true);
9406 * Loads data from a passed data block. A Reader which understands the format of the data
9407 * must have been configured in the constructor.
9408 * @param {Object} data The data block from which to read the Records. The format of the data expected
9409 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9410 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9412 loadData : function(o, append){
9413 var r = this.reader.readRecords(o);
9414 this.loadRecords(r, {add: append}, true);
9418 * Gets the number of cached records.
9420 * <em>If using paging, this may not be the total size of the dataset. If the data object
9421 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9422 * the data set size</em>
9424 getCount : function(){
9425 return this.data.length || 0;
9429 * Gets the total number of records in the dataset as returned by the server.
9431 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9432 * the dataset size</em>
9434 getTotalCount : function(){
9435 return this.totalLength || 0;
9439 * Returns the sort state of the Store as an object with two properties:
9441 field {String} The name of the field by which the Records are sorted
9442 direction {String} The sort order, "ASC" or "DESC"
9445 getSortState : function(){
9446 return this.sortInfo;
9450 applySort : function(){
9451 if(this.sortInfo && !this.remoteSort){
9452 var s = this.sortInfo, f = s.field;
9453 var st = this.fields.get(f).sortType;
9454 var fn = function(r1, r2){
9455 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9456 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9458 this.data.sort(s.direction, fn);
9459 if(this.snapshot && this.snapshot != this.data){
9460 this.snapshot.sort(s.direction, fn);
9466 * Sets the default sort column and order to be used by the next load operation.
9467 * @param {String} fieldName The name of the field to sort by.
9468 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9470 setDefaultSort : function(field, dir){
9471 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9476 * If remote sorting is used, the sort is performed on the server, and the cache is
9477 * reloaded. If local sorting is used, the cache is sorted internally.
9478 * @param {String} fieldName The name of the field to sort by.
9479 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9481 sort : function(fieldName, dir){
9482 var f = this.fields.get(fieldName);
9484 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9486 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9487 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9492 this.sortToggle[f.name] = dir;
9493 this.sortInfo = {field: f.name, direction: dir};
9494 if(!this.remoteSort){
9496 this.fireEvent("datachanged", this);
9498 this.load(this.lastOptions);
9503 * Calls the specified function for each of the Records in the cache.
9504 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9505 * Returning <em>false</em> aborts and exits the iteration.
9506 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9508 each : function(fn, scope){
9509 this.data.each(fn, scope);
9513 * Gets all records modified since the last commit. Modified records are persisted across load operations
9514 * (e.g., during paging).
9515 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9517 getModifiedRecords : function(){
9518 return this.modified;
9522 createFilterFn : function(property, value, anyMatch){
9523 if(!value.exec){ // not a regex
9524 value = String(value);
9525 if(value.length == 0){
9528 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9532 return value.test(r.data[property]);
9537 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9538 * @param {String} property A field on your records
9539 * @param {Number} start The record index to start at (defaults to 0)
9540 * @param {Number} end The last record index to include (defaults to length - 1)
9541 * @return {Number} The sum
9543 sum : function(property, start, end){
9544 var rs = this.data.items, v = 0;
9546 end = (end || end === 0) ? end : rs.length-1;
9548 for(var i = start; i <= end; i++){
9549 v += (rs[i].data[property] || 0);
9555 * Filter the records by a specified property.
9556 * @param {String} field A field on your records
9557 * @param {String/RegExp} value Either a string that the field
9558 * should start with or a RegExp to test against the field
9559 * @param {Boolean} anyMatch True to match any part not just the beginning
9561 filter : function(property, value, anyMatch){
9563 if(typeof(property) == 'string'){
9564 var fn = this.createFilterFn(property, value, anyMatch);
9565 return fn ? this.filterBy(fn) : this.clearFilter();
9573 Roo.each(property, function(p){
9574 if(anyMatch == true){
9575 afn.push(_this.createFilterFn(p, value, true));
9578 fn.push(_this.createFilterFn(p, value, false));
9581 if(!fn.length && !afn.length){
9582 return this.clearFilter();
9585 this.snapshot = this.snapshot || this.data;
9587 var filterData = [];
9589 Roo.each(fn, function(f){
9590 filterData.push(_this.queryBy(f, _this));
9593 Roo.each(afn, function(f){
9594 filterData.push(_this.queryBy(f, _this));
9597 var data = this.snapshot || this.data;
9599 var r = new Roo.util.MixedCollection();
9600 r.getKey = data.getKey;
9604 Roo.each(filterData, function(d){
9605 var k = d.keys, it = d.items;
9606 for(var i = 0, len = it.length; i < len; i++){
9607 if(keys.indexOf(k[i]) == -1){
9614 this.fireEvent("datachanged", this);
9618 * Filter by a function. The specified function will be called with each
9619 * record in this data source. If the function returns true the record is included,
9620 * otherwise it is filtered.
9621 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9622 * @param {Object} scope (optional) The scope of the function (defaults to this)
9624 filterBy : function(fn, scope){
9625 this.snapshot = this.snapshot || this.data;
9626 this.data = this.queryBy(fn, scope||this);
9627 this.fireEvent("datachanged", this);
9631 * Query the records by a specified property.
9632 * @param {String} field A field on your records
9633 * @param {String/RegExp} value Either a string that the field
9634 * should start with or a RegExp to test against the field
9635 * @param {Boolean} anyMatch True to match any part not just the beginning
9636 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9638 query : function(property, value, anyMatch){
9639 var fn = this.createFilterFn(property, value, anyMatch);
9640 return fn ? this.queryBy(fn) : this.data.clone();
9644 * Query by a function. The specified function will be called with each
9645 * record in this data source. If the function returns true the record is included
9647 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9648 * @param {Object} scope (optional) The scope of the function (defaults to this)
9649 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9651 queryBy : function(fn, scope){
9652 var data = this.snapshot || this.data;
9653 return data.filterBy(fn, scope||this);
9657 * Collects unique values for a particular dataIndex from this store.
9658 * @param {String} dataIndex The property to collect
9659 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9660 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9661 * @return {Array} An array of the unique values
9663 collect : function(dataIndex, allowNull, bypassFilter){
9664 var d = (bypassFilter === true && this.snapshot) ?
9665 this.snapshot.items : this.data.items;
9666 var v, sv, r = [], l = {};
9667 for(var i = 0, len = d.length; i < len; i++){
9668 v = d[i].data[dataIndex];
9670 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9679 * Revert to a view of the Record cache with no filtering applied.
9680 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9682 clearFilter : function(suppressEvent){
9683 if(this.snapshot && this.snapshot != this.data){
9684 this.data = this.snapshot;
9685 delete this.snapshot;
9686 if(suppressEvent !== true){
9687 this.fireEvent("datachanged", this);
9693 afterEdit : function(record){
9694 if(this.modified.indexOf(record) == -1){
9695 this.modified.push(record);
9697 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9701 afterReject : function(record){
9702 this.modified.remove(record);
9703 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9707 afterCommit : function(record){
9708 this.modified.remove(record);
9709 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9713 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9714 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9716 commitChanges : function(){
9717 var m = this.modified.slice(0);
9719 for(var i = 0, len = m.length; i < len; i++){
9725 * Cancel outstanding changes on all changed records.
9727 rejectChanges : function(){
9728 var m = this.modified.slice(0);
9730 for(var i = 0, len = m.length; i < len; i++){
9735 onMetaChange : function(meta, rtype, o){
9736 this.recordType = rtype;
9737 this.fields = rtype.prototype.fields;
9738 delete this.snapshot;
9739 this.sortInfo = meta.sortInfo || this.sortInfo;
9741 this.fireEvent('metachange', this, this.reader.meta);
9744 moveIndex : function(data, type)
9746 var index = this.indexOf(data);
9748 var newIndex = index + type;
9752 this.insert(newIndex, data);
9757 * Ext JS Library 1.1.1
9758 * Copyright(c) 2006-2007, Ext JS, LLC.
9760 * Originally Released Under LGPL - original licence link has changed is not relivant.
9763 * <script type="text/javascript">
9767 * @class Roo.data.SimpleStore
9768 * @extends Roo.data.Store
9769 * Small helper class to make creating Stores from Array data easier.
9770 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9771 * @cfg {Array} fields An array of field definition objects, or field name strings.
9772 * @cfg {Array} data The multi-dimensional array of data
9774 * @param {Object} config
9776 Roo.data.SimpleStore = function(config){
9777 Roo.data.SimpleStore.superclass.constructor.call(this, {
9779 reader: new Roo.data.ArrayReader({
9782 Roo.data.Record.create(config.fields)
9784 proxy : new Roo.data.MemoryProxy(config.data)
9788 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9790 * Ext JS Library 1.1.1
9791 * Copyright(c) 2006-2007, Ext JS, LLC.
9793 * Originally Released Under LGPL - original licence link has changed is not relivant.
9796 * <script type="text/javascript">
9801 * @extends Roo.data.Store
9802 * @class Roo.data.JsonStore
9803 * Small helper class to make creating Stores for JSON data easier. <br/>
9805 var store = new Roo.data.JsonStore({
9806 url: 'get-images.php',
9808 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9811 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9812 * JsonReader and HttpProxy (unless inline data is provided).</b>
9813 * @cfg {Array} fields An array of field definition objects, or field name strings.
9815 * @param {Object} config
9817 Roo.data.JsonStore = function(c){
9818 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9819 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9820 reader: new Roo.data.JsonReader(c, c.fields)
9823 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9825 * Ext JS Library 1.1.1
9826 * Copyright(c) 2006-2007, Ext JS, LLC.
9828 * Originally Released Under LGPL - original licence link has changed is not relivant.
9831 * <script type="text/javascript">
9835 Roo.data.Field = function(config){
9836 if(typeof config == "string"){
9837 config = {name: config};
9839 Roo.apply(this, config);
9845 var st = Roo.data.SortTypes;
9846 // named sortTypes are supported, here we look them up
9847 if(typeof this.sortType == "string"){
9848 this.sortType = st[this.sortType];
9851 // set default sortType for strings and dates
9855 this.sortType = st.asUCString;
9858 this.sortType = st.asDate;
9861 this.sortType = st.none;
9866 var stripRe = /[\$,%]/g;
9868 // prebuilt conversion function for this field, instead of
9869 // switching every time we're reading a value
9871 var cv, dateFormat = this.dateFormat;
9876 cv = function(v){ return v; };
9879 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9883 return v !== undefined && v !== null && v !== '' ?
9884 parseInt(String(v).replace(stripRe, ""), 10) : '';
9889 return v !== undefined && v !== null && v !== '' ?
9890 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9895 cv = function(v){ return v === true || v === "true" || v == 1; };
9902 if(v instanceof Date){
9906 if(dateFormat == "timestamp"){
9907 return new Date(v*1000);
9909 return Date.parseDate(v, dateFormat);
9911 var parsed = Date.parse(v);
9912 return parsed ? new Date(parsed) : null;
9921 Roo.data.Field.prototype = {
9929 * Ext JS Library 1.1.1
9930 * Copyright(c) 2006-2007, Ext JS, LLC.
9932 * Originally Released Under LGPL - original licence link has changed is not relivant.
9935 * <script type="text/javascript">
9938 // Base class for reading structured data from a data source. This class is intended to be
9939 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9942 * @class Roo.data.DataReader
9943 * Base class for reading structured data from a data source. This class is intended to be
9944 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9947 Roo.data.DataReader = function(meta, recordType){
9951 this.recordType = recordType instanceof Array ?
9952 Roo.data.Record.create(recordType) : recordType;
9955 Roo.data.DataReader.prototype = {
9957 * Create an empty record
9958 * @param {Object} data (optional) - overlay some values
9959 * @return {Roo.data.Record} record created.
9961 newRow : function(d) {
9963 this.recordType.prototype.fields.each(function(c) {
9965 case 'int' : da[c.name] = 0; break;
9966 case 'date' : da[c.name] = new Date(); break;
9967 case 'float' : da[c.name] = 0.0; break;
9968 case 'boolean' : da[c.name] = false; break;
9969 default : da[c.name] = ""; break;
9973 return new this.recordType(Roo.apply(da, d));
9978 * Ext JS Library 1.1.1
9979 * Copyright(c) 2006-2007, Ext JS, LLC.
9981 * Originally Released Under LGPL - original licence link has changed is not relivant.
9984 * <script type="text/javascript">
9988 * @class Roo.data.DataProxy
9989 * @extends Roo.data.Observable
9990 * This class is an abstract base class for implementations which provide retrieval of
9991 * unformatted data objects.<br>
9993 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9994 * (of the appropriate type which knows how to parse the data object) to provide a block of
9995 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9997 * Custom implementations must implement the load method as described in
9998 * {@link Roo.data.HttpProxy#load}.
10000 Roo.data.DataProxy = function(){
10003 * @event beforeload
10004 * Fires before a network request is made to retrieve a data object.
10005 * @param {Object} This DataProxy object.
10006 * @param {Object} params The params parameter to the load function.
10011 * Fires before the load method's callback is called.
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.
10018 * @event loadexception
10019 * Fires if an Exception occurs during data retrieval.
10020 * @param {Object} This DataProxy object.
10021 * @param {Object} o The data object.
10022 * @param {Object} arg The callback argument object passed to the load function.
10023 * @param {Object} e The Exception.
10025 loadexception : true
10027 Roo.data.DataProxy.superclass.constructor.call(this);
10030 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10033 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10037 * Ext JS Library 1.1.1
10038 * Copyright(c) 2006-2007, Ext JS, LLC.
10040 * Originally Released Under LGPL - original licence link has changed is not relivant.
10043 * <script type="text/javascript">
10046 * @class Roo.data.MemoryProxy
10047 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10048 * to the Reader when its load method is called.
10050 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10052 Roo.data.MemoryProxy = function(data){
10056 Roo.data.MemoryProxy.superclass.constructor.call(this);
10060 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10062 * Load data from the requested source (in this case an in-memory
10063 * data object passed to the constructor), read the data object into
10064 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10065 * process that block using the passed callback.
10066 * @param {Object} params This parameter is not used by the MemoryProxy class.
10067 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10068 * object into a block of Roo.data.Records.
10069 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10070 * The function must be passed <ul>
10071 * <li>The Record block object</li>
10072 * <li>The "arg" argument from the load function</li>
10073 * <li>A boolean success indicator</li>
10075 * @param {Object} scope The scope in which to call the callback
10076 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10078 load : function(params, reader, callback, scope, arg){
10079 params = params || {};
10082 result = reader.readRecords(this.data);
10084 this.fireEvent("loadexception", this, arg, null, e);
10085 callback.call(scope, null, arg, false);
10088 callback.call(scope, result, arg, true);
10092 update : function(params, records){
10097 * Ext JS Library 1.1.1
10098 * Copyright(c) 2006-2007, Ext JS, LLC.
10100 * Originally Released Under LGPL - original licence link has changed is not relivant.
10103 * <script type="text/javascript">
10106 * @class Roo.data.HttpProxy
10107 * @extends Roo.data.DataProxy
10108 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10109 * configured to reference a certain URL.<br><br>
10111 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10112 * from which the running page was served.<br><br>
10114 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10116 * Be aware that to enable the browser to parse an XML document, the server must set
10117 * the Content-Type header in the HTTP response to "text/xml".
10119 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10120 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10121 * will be used to make the request.
10123 Roo.data.HttpProxy = function(conn){
10124 Roo.data.HttpProxy.superclass.constructor.call(this);
10125 // is conn a conn config or a real conn?
10127 this.useAjax = !conn || !conn.events;
10131 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10132 // thse are take from connection...
10135 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10138 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10139 * extra parameters to each request made by this object. (defaults to undefined)
10142 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10143 * to each request made by this object. (defaults to undefined)
10146 * @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)
10149 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10152 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10158 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10162 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10163 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10164 * a finer-grained basis than the DataProxy events.
10166 getConnection : function(){
10167 return this.useAjax ? Roo.Ajax : this.conn;
10171 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10172 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10173 * process that block using the passed callback.
10174 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10175 * for the request to the remote server.
10176 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10177 * object into a block of Roo.data.Records.
10178 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10179 * The function must be passed <ul>
10180 * <li>The Record block object</li>
10181 * <li>The "arg" argument from the load function</li>
10182 * <li>A boolean success indicator</li>
10184 * @param {Object} scope The scope in which to call the callback
10185 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10187 load : function(params, reader, callback, scope, arg){
10188 if(this.fireEvent("beforeload", this, params) !== false){
10190 params : params || {},
10192 callback : callback,
10197 callback : this.loadResponse,
10201 Roo.applyIf(o, this.conn);
10202 if(this.activeRequest){
10203 Roo.Ajax.abort(this.activeRequest);
10205 this.activeRequest = Roo.Ajax.request(o);
10207 this.conn.request(o);
10210 callback.call(scope||this, null, arg, false);
10215 loadResponse : function(o, success, response){
10216 delete this.activeRequest;
10218 this.fireEvent("loadexception", this, o, response);
10219 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10224 result = o.reader.read(response);
10226 this.fireEvent("loadexception", this, o, response, e);
10227 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10231 this.fireEvent("load", this, o, o.request.arg);
10232 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10236 update : function(dataSet){
10241 updateResponse : function(dataSet){
10246 * Ext JS Library 1.1.1
10247 * Copyright(c) 2006-2007, Ext JS, LLC.
10249 * Originally Released Under LGPL - original licence link has changed is not relivant.
10252 * <script type="text/javascript">
10256 * @class Roo.data.ScriptTagProxy
10257 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10258 * other than the originating domain of the running page.<br><br>
10260 * <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
10261 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10263 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10264 * source code that is used as the source inside a <script> tag.<br><br>
10266 * In order for the browser to process the returned data, the server must wrap the data object
10267 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10268 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10269 * depending on whether the callback name was passed:
10272 boolean scriptTag = false;
10273 String cb = request.getParameter("callback");
10276 response.setContentType("text/javascript");
10278 response.setContentType("application/x-json");
10280 Writer out = response.getWriter();
10282 out.write(cb + "(");
10284 out.print(dataBlock.toJsonString());
10291 * @param {Object} config A configuration object.
10293 Roo.data.ScriptTagProxy = function(config){
10294 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10295 Roo.apply(this, config);
10296 this.head = document.getElementsByTagName("head")[0];
10299 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10301 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10303 * @cfg {String} url The URL from which to request the data object.
10306 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10310 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10311 * the server the name of the callback function set up by the load call to process the returned data object.
10312 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10313 * javascript output which calls this named function passing the data object as its only parameter.
10315 callbackParam : "callback",
10317 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10318 * name to the request.
10323 * Load data from the configured URL, read the data object into
10324 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10325 * process that block using the passed callback.
10326 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10327 * for the request to the remote server.
10328 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10329 * object into a block of Roo.data.Records.
10330 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10331 * The function must be passed <ul>
10332 * <li>The Record block object</li>
10333 * <li>The "arg" argument from the load function</li>
10334 * <li>A boolean success indicator</li>
10336 * @param {Object} scope The scope in which to call the callback
10337 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10339 load : function(params, reader, callback, scope, arg){
10340 if(this.fireEvent("beforeload", this, params) !== false){
10342 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10344 var url = this.url;
10345 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10347 url += "&_dc=" + (new Date().getTime());
10349 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10352 cb : "stcCallback"+transId,
10353 scriptId : "stcScript"+transId,
10357 callback : callback,
10363 window[trans.cb] = function(o){
10364 conn.handleResponse(o, trans);
10367 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10369 if(this.autoAbort !== false){
10373 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10375 var script = document.createElement("script");
10376 script.setAttribute("src", url);
10377 script.setAttribute("type", "text/javascript");
10378 script.setAttribute("id", trans.scriptId);
10379 this.head.appendChild(script);
10381 this.trans = trans;
10383 callback.call(scope||this, null, arg, false);
10388 isLoading : function(){
10389 return this.trans ? true : false;
10393 * Abort the current server request.
10395 abort : function(){
10396 if(this.isLoading()){
10397 this.destroyTrans(this.trans);
10402 destroyTrans : function(trans, isLoaded){
10403 this.head.removeChild(document.getElementById(trans.scriptId));
10404 clearTimeout(trans.timeoutId);
10406 window[trans.cb] = undefined;
10408 delete window[trans.cb];
10411 // if hasn't been loaded, wait for load to remove it to prevent script error
10412 window[trans.cb] = function(){
10413 window[trans.cb] = undefined;
10415 delete window[trans.cb];
10422 handleResponse : function(o, trans){
10423 this.trans = false;
10424 this.destroyTrans(trans, true);
10427 result = trans.reader.readRecords(o);
10429 this.fireEvent("loadexception", this, o, trans.arg, e);
10430 trans.callback.call(trans.scope||window, null, trans.arg, false);
10433 this.fireEvent("load", this, o, trans.arg);
10434 trans.callback.call(trans.scope||window, result, trans.arg, true);
10438 handleFailure : function(trans){
10439 this.trans = false;
10440 this.destroyTrans(trans, false);
10441 this.fireEvent("loadexception", this, null, trans.arg);
10442 trans.callback.call(trans.scope||window, null, trans.arg, false);
10446 * Ext JS Library 1.1.1
10447 * Copyright(c) 2006-2007, Ext JS, LLC.
10449 * Originally Released Under LGPL - original licence link has changed is not relivant.
10452 * <script type="text/javascript">
10456 * @class Roo.data.JsonReader
10457 * @extends Roo.data.DataReader
10458 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10459 * based on mappings in a provided Roo.data.Record constructor.
10461 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10462 * in the reply previously.
10467 var RecordDef = Roo.data.Record.create([
10468 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10469 {name: 'occupation'} // This field will use "occupation" as the mapping.
10471 var myReader = new Roo.data.JsonReader({
10472 totalProperty: "results", // The property which contains the total dataset size (optional)
10473 root: "rows", // The property which contains an Array of row objects
10474 id: "id" // The property within each row object that provides an ID for the record (optional)
10478 * This would consume a JSON file like this:
10480 { 'results': 2, 'rows': [
10481 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10482 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10485 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10486 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10487 * paged from the remote server.
10488 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10489 * @cfg {String} root name of the property which contains the Array of row objects.
10490 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10492 * Create a new JsonReader
10493 * @param {Object} meta Metadata configuration options
10494 * @param {Object} recordType Either an Array of field definition objects,
10495 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10497 Roo.data.JsonReader = function(meta, recordType){
10500 // set some defaults:
10501 Roo.applyIf(meta, {
10502 totalProperty: 'total',
10503 successProperty : 'success',
10508 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10510 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10513 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10514 * Used by Store query builder to append _requestMeta to params.
10517 metaFromRemote : false,
10519 * This method is only used by a DataProxy which has retrieved data from a remote server.
10520 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10521 * @return {Object} data A data block which is used by an Roo.data.Store object as
10522 * a cache of Roo.data.Records.
10524 read : function(response){
10525 var json = response.responseText;
10527 var o = /* eval:var:o */ eval("("+json+")");
10529 throw {message: "JsonReader.read: Json object not found"};
10535 this.metaFromRemote = true;
10536 this.meta = o.metaData;
10537 this.recordType = Roo.data.Record.create(o.metaData.fields);
10538 this.onMetaChange(this.meta, this.recordType, o);
10540 return this.readRecords(o);
10543 // private function a store will implement
10544 onMetaChange : function(meta, recordType, o){
10551 simpleAccess: function(obj, subsc) {
10558 getJsonAccessor: function(){
10560 return function(expr) {
10562 return(re.test(expr))
10563 ? new Function("obj", "return obj." + expr)
10568 return Roo.emptyFn;
10573 * Create a data block containing Roo.data.Records from an XML document.
10574 * @param {Object} o An object which contains an Array of row objects in the property specified
10575 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10576 * which contains the total size of the dataset.
10577 * @return {Object} data A data block which is used by an Roo.data.Store object as
10578 * a cache of Roo.data.Records.
10580 readRecords : function(o){
10582 * After any data loads, the raw JSON data is available for further custom processing.
10586 var s = this.meta, Record = this.recordType,
10587 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10589 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10591 if(s.totalProperty) {
10592 this.getTotal = this.getJsonAccessor(s.totalProperty);
10594 if(s.successProperty) {
10595 this.getSuccess = this.getJsonAccessor(s.successProperty);
10597 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10599 var g = this.getJsonAccessor(s.id);
10600 this.getId = function(rec) {
10602 return (r === undefined || r === "") ? null : r;
10605 this.getId = function(){return null;};
10608 for(var jj = 0; jj < fl; jj++){
10610 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10611 this.ef[jj] = this.getJsonAccessor(map);
10615 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10616 if(s.totalProperty){
10617 var vt = parseInt(this.getTotal(o), 10);
10622 if(s.successProperty){
10623 var vs = this.getSuccess(o);
10624 if(vs === false || vs === 'false'){
10629 for(var i = 0; i < c; i++){
10632 var id = this.getId(n);
10633 for(var j = 0; j < fl; j++){
10635 var v = this.ef[j](n);
10637 Roo.log('missing convert for ' + f.name);
10641 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10643 var record = new Record(values, id);
10645 records[i] = record;
10651 totalRecords : totalRecords
10656 * Ext JS Library 1.1.1
10657 * Copyright(c) 2006-2007, Ext JS, LLC.
10659 * Originally Released Under LGPL - original licence link has changed is not relivant.
10662 * <script type="text/javascript">
10666 * @class Roo.data.ArrayReader
10667 * @extends Roo.data.DataReader
10668 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10669 * Each element of that Array represents a row of data fields. The
10670 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10671 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10675 var RecordDef = Roo.data.Record.create([
10676 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10677 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10679 var myReader = new Roo.data.ArrayReader({
10680 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10684 * This would consume an Array like this:
10686 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10688 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10690 * Create a new JsonReader
10691 * @param {Object} meta Metadata configuration options.
10692 * @param {Object} recordType Either an Array of field definition objects
10693 * as specified to {@link Roo.data.Record#create},
10694 * or an {@link Roo.data.Record} object
10695 * created using {@link Roo.data.Record#create}.
10697 Roo.data.ArrayReader = function(meta, recordType){
10698 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10701 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10703 * Create a data block containing Roo.data.Records from an XML document.
10704 * @param {Object} o An Array of row objects which represents the dataset.
10705 * @return {Object} data A data block which is used by an Roo.data.Store object as
10706 * a cache of Roo.data.Records.
10708 readRecords : function(o){
10709 var sid = this.meta ? this.meta.id : null;
10710 var recordType = this.recordType, fields = recordType.prototype.fields;
10713 for(var i = 0; i < root.length; i++){
10716 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10717 for(var j = 0, jlen = fields.length; j < jlen; j++){
10718 var f = fields.items[j];
10719 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10720 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10722 values[f.name] = v;
10724 var record = new recordType(values, id);
10726 records[records.length] = record;
10730 totalRecords : records.length
10739 * @class Roo.bootstrap.ComboBox
10740 * @extends Roo.bootstrap.TriggerField
10741 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10742 * @cfg {Boolean} append (true|false) default false
10743 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10744 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10745 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10746 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10747 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10748 * @cfg {Boolean} anyMatch (true|false) any match when filter default false
10750 * Create a new ComboBox.
10751 * @param {Object} config Configuration options
10753 Roo.bootstrap.ComboBox = function(config){
10754 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10758 * Fires when the dropdown list is expanded
10759 * @param {Roo.bootstrap.ComboBox} combo This combo box
10764 * Fires when the dropdown list is collapsed
10765 * @param {Roo.bootstrap.ComboBox} combo This combo box
10769 * @event beforeselect
10770 * Fires before a list item is selected. Return false to cancel the selection.
10771 * @param {Roo.bootstrap.ComboBox} combo This combo box
10772 * @param {Roo.data.Record} record The data record returned from the underlying store
10773 * @param {Number} index The index of the selected item in the dropdown list
10775 'beforeselect' : true,
10778 * Fires when a list item is selected
10779 * @param {Roo.bootstrap.ComboBox} combo This combo box
10780 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10781 * @param {Number} index The index of the selected item in the dropdown list
10785 * @event beforequery
10786 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10787 * The event object passed has these properties:
10788 * @param {Roo.bootstrap.ComboBox} combo This combo box
10789 * @param {String} query The query
10790 * @param {Boolean} forceAll true to force "all" query
10791 * @param {Boolean} cancel true to cancel the query
10792 * @param {Object} e The query event object
10794 'beforequery': true,
10797 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10798 * @param {Roo.bootstrap.ComboBox} combo This combo box
10803 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10804 * @param {Roo.bootstrap.ComboBox} combo This combo box
10805 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10810 * Fires when the remove value from the combobox array
10811 * @param {Roo.bootstrap.ComboBox} combo This combo box
10818 this.tickItems = [];
10820 this.selectedIndex = -1;
10821 if(this.mode == 'local'){
10822 if(config.queryDelay === undefined){
10823 this.queryDelay = 10;
10825 if(config.minChars === undefined){
10831 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10834 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10835 * rendering into an Roo.Editor, defaults to false)
10838 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10839 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10842 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10845 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10846 * the dropdown list (defaults to undefined, with no header element)
10850 * @cfg {String/Roo.Template} tpl The template to use to render the output
10854 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10856 listWidth: undefined,
10858 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10859 * mode = 'remote' or 'text' if mode = 'local')
10861 displayField: undefined,
10864 * @cfg {Array} filterField The filter field name to bind to this CombBox (defaults to undefined if
10866 filterField: undefined,
10869 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10870 * mode = 'remote' or 'value' if mode = 'local').
10871 * Note: use of a valueField requires the user make a selection
10872 * in order for a value to be mapped.
10874 valueField: undefined,
10878 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10879 * field's data value (defaults to the underlying DOM element's name)
10881 hiddenName: undefined,
10883 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10887 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10889 selectedClass: 'active',
10892 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10896 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10897 * anchor positions (defaults to 'tl-bl')
10899 listAlign: 'tl-bl?',
10901 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10905 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10906 * query specified by the allQuery config option (defaults to 'query')
10908 triggerAction: 'query',
10910 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10911 * (defaults to 4, does not apply if editable = false)
10915 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10916 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10920 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10921 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10925 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10926 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10930 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10931 * when editable = true (defaults to false)
10933 selectOnFocus:false,
10935 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10937 queryParam: 'query',
10939 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10940 * when mode = 'remote' (defaults to 'Loading...')
10942 loadingText: 'Loading...',
10944 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10948 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10952 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10953 * traditional select (defaults to true)
10957 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10961 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10965 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10966 * listWidth has a higher value)
10970 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10971 * allow the user to set arbitrary text into the field (defaults to false)
10973 forceSelection:false,
10975 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10976 * if typeAhead = true (defaults to 250)
10978 typeAheadDelay : 250,
10980 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10981 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10983 valueNotFoundText : undefined,
10985 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10987 blockFocus : false,
10990 * @cfg {Boolean} disableClear Disable showing of clear button.
10992 disableClear : false,
10994 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10996 alwaysQuery : false,
10999 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11004 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11006 invalidClass : "has-warning",
11009 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11011 validClass : "has-success",
11014 * @cfg {Boolean} filterSort (true|false) sort the filter result default false
11016 filterSort : false,
11019 * @cfg {String} filterSortDir (ASC|DESC) dir of sort the filter result default ASC
11021 filterSortDir : 'ASC',
11033 btnPosition : 'right',
11034 triggerList : true,
11035 showToggleBtn : true,
11037 // element that contains real text value.. (when hidden is used..)
11039 getAutoCreate : function()
11046 if(!this.tickable){
11047 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11052 * ComboBox with tickable selections
11055 var align = this.labelAlign || this.parentLabelAlign();
11058 cls : 'form-group roo-combobox-tickable' //input-group
11063 cls : 'tickable-buttons',
11068 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11075 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11082 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11089 buttons.cn.unshift({
11091 cls: 'select2-search-field-input'
11097 Roo.each(buttons.cn, function(c){
11099 c.cls += ' btn-' + _this.size;
11102 if (_this.disabled) {
11113 cls: 'form-hidden-field'
11117 cls: 'select2-choices',
11121 cls: 'select2-search-field',
11133 cls: 'select2-container input-group select2-container-multi',
11138 // cls: 'typeahead typeahead-long dropdown-menu',
11139 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11144 if(this.hasFeedback && !this.allowBlank){
11148 cls: 'glyphicon form-control-feedback'
11151 combobox.cn.push(feedback);
11154 if (align ==='left' && this.fieldLabel.length) {
11156 Roo.log("left and has label");
11162 cls : 'control-label col-sm-' + this.labelWidth,
11163 html : this.fieldLabel
11167 cls : "col-sm-" + (12 - this.labelWidth),
11174 } else if ( this.fieldLabel.length) {
11180 //cls : 'input-group-addon',
11181 html : this.fieldLabel
11191 Roo.log(" no label && no align");
11198 ['xs','sm','md','lg'].map(function(size){
11199 if (settings[size]) {
11200 cfg.cls += ' col-' + size + '-' + settings[size];
11209 initEvents: function()
11213 throw "can not find store for combo";
11215 this.store = Roo.factory(this.store, Roo.data);
11218 this.initTickableEvents();
11222 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11224 if(this.hiddenName){
11226 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11228 this.hiddenField.dom.value =
11229 this.hiddenValue !== undefined ? this.hiddenValue :
11230 this.value !== undefined ? this.value : '';
11232 // prevent input submission
11233 this.el.dom.removeAttribute('name');
11234 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11239 // this.el.dom.setAttribute('autocomplete', 'off');
11242 var cls = 'x-combo-list';
11244 //this.list = new Roo.Layer({
11245 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11251 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11252 _this.list.setWidth(lw);
11255 this.list.on('mouseover', this.onViewOver, this);
11256 this.list.on('mousemove', this.onViewMove, this);
11258 this.list.on('scroll', this.onViewScroll, this);
11261 this.list.swallowEvent('mousewheel');
11262 this.assetHeight = 0;
11265 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11266 this.assetHeight += this.header.getHeight();
11269 this.innerList = this.list.createChild({cls:cls+'-inner'});
11270 this.innerList.on('mouseover', this.onViewOver, this);
11271 this.innerList.on('mousemove', this.onViewMove, this);
11272 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11274 if(this.allowBlank && !this.pageSize && !this.disableClear){
11275 this.footer = this.list.createChild({cls:cls+'-ft'});
11276 this.pageTb = new Roo.Toolbar(this.footer);
11280 this.footer = this.list.createChild({cls:cls+'-ft'});
11281 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11282 {pageSize: this.pageSize});
11286 if (this.pageTb && this.allowBlank && !this.disableClear) {
11288 this.pageTb.add(new Roo.Toolbar.Fill(), {
11289 cls: 'x-btn-icon x-btn-clear',
11291 handler: function()
11294 _this.clearValue();
11295 _this.onSelect(false, -1);
11300 this.assetHeight += this.footer.getHeight();
11305 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11308 this.view = new Roo.View(this.list, this.tpl, {
11309 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11311 //this.view.wrapEl.setDisplayed(false);
11312 this.view.on('click', this.onViewClick, this);
11316 this.store.on('beforeload', this.onBeforeLoad, this);
11317 this.store.on('load', this.onLoad, this);
11318 this.store.on('loadexception', this.onLoadException, this);
11320 if(this.resizable){
11321 this.resizer = new Roo.Resizable(this.list, {
11322 pinned:true, handles:'se'
11324 this.resizer.on('resize', function(r, w, h){
11325 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11326 this.listWidth = w;
11327 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11328 this.restrictHeight();
11330 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11333 if(!this.editable){
11334 this.editable = true;
11335 this.setEditable(false);
11340 if (typeof(this.events.add.listeners) != 'undefined') {
11342 this.addicon = this.wrap.createChild(
11343 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11345 this.addicon.on('click', function(e) {
11346 this.fireEvent('add', this);
11349 if (typeof(this.events.edit.listeners) != 'undefined') {
11351 this.editicon = this.wrap.createChild(
11352 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11353 if (this.addicon) {
11354 this.editicon.setStyle('margin-left', '40px');
11356 this.editicon.on('click', function(e) {
11358 // we fire even if inothing is selected..
11359 this.fireEvent('edit', this, this.lastData );
11365 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11366 "up" : function(e){
11367 this.inKeyMode = true;
11371 "down" : function(e){
11372 if(!this.isExpanded()){
11373 this.onTriggerClick();
11375 this.inKeyMode = true;
11380 "enter" : function(e){
11381 // this.onViewClick();
11385 if(this.fireEvent("specialkey", this, e)){
11386 this.onViewClick(false);
11392 "esc" : function(e){
11396 "tab" : function(e){
11399 if(this.fireEvent("specialkey", this, e)){
11400 this.onViewClick(false);
11408 doRelay : function(foo, bar, hname){
11409 if(hname == 'down' || this.scope.isExpanded()){
11410 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11419 this.queryDelay = Math.max(this.queryDelay || 10,
11420 this.mode == 'local' ? 10 : 250);
11423 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11425 if(this.typeAhead){
11426 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11428 if(this.editable !== false){
11429 this.inputEl().on("keyup", this.onKeyUp, this);
11431 if(this.forceSelection){
11432 this.inputEl().on('blur', this.doForce, this);
11436 this.choices = this.el.select('ul.select2-choices', true).first();
11437 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11441 initTickableEvents: function()
11445 if(this.hiddenName){
11447 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11449 this.hiddenField.dom.value =
11450 this.hiddenValue !== undefined ? this.hiddenValue :
11451 this.value !== undefined ? this.value : '';
11453 // prevent input submission
11454 this.el.dom.removeAttribute('name');
11455 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11460 // this.list = this.el.select('ul.dropdown-menu',true).first();
11462 this.choices = this.el.select('ul.select2-choices', true).first();
11463 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11464 if(this.triggerList){
11465 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11468 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11469 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11471 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11472 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11474 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11475 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11477 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11478 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11479 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11482 this.cancelBtn.hide();
11487 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11488 _this.list.setWidth(lw);
11491 this.list.on('mouseover', this.onViewOver, this);
11492 this.list.on('mousemove', this.onViewMove, this);
11494 this.list.on('scroll', this.onViewScroll, this);
11497 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11500 this.view = new Roo.View(this.list, this.tpl, {
11501 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11504 //this.view.wrapEl.setDisplayed(false);
11505 this.view.on('click', this.onViewClick, this);
11509 this.store.on('beforeload', this.onBeforeLoad, this);
11510 this.store.on('load', this.onLoad, this);
11511 this.store.on('loadexception', this.onLoadException, this);
11514 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11515 "up" : function(e){
11516 this.inKeyMode = true;
11520 "down" : function(e){
11521 this.inKeyMode = true;
11525 "enter" : function(e){
11526 if(this.fireEvent("specialkey", this, e)){
11527 this.onViewClick(false);
11533 "esc" : function(e){
11534 this.onTickableFooterButtonClick(e, false, false);
11537 "tab" : function(e){
11538 this.fireEvent("specialkey", this, e);
11540 this.onTickableFooterButtonClick(e, false, false);
11547 doRelay : function(e, fn, key){
11548 if(this.scope.isExpanded()){
11549 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11558 this.queryDelay = Math.max(this.queryDelay || 10,
11559 this.mode == 'local' ? 10 : 250);
11562 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11564 if(this.typeAhead){
11565 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11568 if(this.editable !== false){
11569 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11574 onDestroy : function(){
11576 this.view.setStore(null);
11577 this.view.el.removeAllListeners();
11578 this.view.el.remove();
11579 this.view.purgeListeners();
11582 this.list.dom.innerHTML = '';
11586 this.store.un('beforeload', this.onBeforeLoad, this);
11587 this.store.un('load', this.onLoad, this);
11588 this.store.un('loadexception', this.onLoadException, this);
11590 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11594 fireKey : function(e){
11595 if(e.isNavKeyPress() && !this.list.isVisible()){
11596 this.fireEvent("specialkey", this, e);
11601 onResize: function(w, h){
11602 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11604 // if(typeof w != 'number'){
11605 // // we do not handle it!?!?
11608 // var tw = this.trigger.getWidth();
11609 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11610 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11612 // this.inputEl().setWidth( this.adjustWidth('input', x));
11614 // //this.trigger.setStyle('left', x+'px');
11616 // if(this.list && this.listWidth === undefined){
11617 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11618 // this.list.setWidth(lw);
11619 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11627 * Allow or prevent the user from directly editing the field text. If false is passed,
11628 * the user will only be able to select from the items defined in the dropdown list. This method
11629 * is the runtime equivalent of setting the 'editable' config option at config time.
11630 * @param {Boolean} value True to allow the user to directly edit the field text
11632 setEditable : function(value){
11633 if(value == this.editable){
11636 this.editable = value;
11638 this.inputEl().dom.setAttribute('readOnly', true);
11639 this.inputEl().on('mousedown', this.onTriggerClick, this);
11640 this.inputEl().addClass('x-combo-noedit');
11642 this.inputEl().dom.setAttribute('readOnly', false);
11643 this.inputEl().un('mousedown', this.onTriggerClick, this);
11644 this.inputEl().removeClass('x-combo-noedit');
11650 onBeforeLoad : function(combo,opts){
11651 if(!this.hasFocus){
11655 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11657 this.restrictHeight();
11658 this.selectedIndex = -1;
11662 onLoad : function(){
11664 this.hasQuery = false;
11666 if(!this.hasFocus){
11670 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11671 this.loading.hide();
11674 if(this.store.getCount() > 0){
11676 this.restrictHeight();
11677 if(this.lastQuery == this.allQuery){
11678 if(this.editable && !this.tickable){
11679 this.inputEl().dom.select();
11683 !this.selectByValue(this.value, true) &&
11686 !this.store.lastOptions ||
11687 typeof(this.store.lastOptions.add) == 'undefined' ||
11688 this.store.lastOptions.add != true
11691 this.select(0, true);
11694 if(this.autoFocus){
11697 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11698 this.taTask.delay(this.typeAheadDelay);
11702 this.onEmptyResults();
11708 onLoadException : function()
11710 this.hasQuery = false;
11712 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11713 this.loading.hide();
11716 if(this.tickable && this.editable){
11722 Roo.log(this.store.reader.jsonData);
11723 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11725 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11731 onTypeAhead : function(){
11732 if(this.store.getCount() > 0){
11733 var r = this.store.getAt(0);
11734 var newValue = r.data[this.displayField];
11735 var len = newValue.length;
11736 var selStart = this.getRawValue().length;
11738 if(selStart != len){
11739 this.setRawValue(newValue);
11740 this.selectText(selStart, newValue.length);
11746 onSelect : function(record, index){
11748 if(this.fireEvent('beforeselect', this, record, index) !== false){
11750 this.setFromData(index > -1 ? record.data : false);
11753 this.fireEvent('select', this, record, index);
11758 * Returns the currently selected field value or empty string if no value is set.
11759 * @return {String} value The selected value
11761 getValue : function(){
11764 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11767 if(this.valueField){
11768 return typeof this.value != 'undefined' ? this.value : '';
11770 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11775 * Clears any text/value currently set in the field
11777 clearValue : function(){
11778 if(this.hiddenField){
11779 this.hiddenField.dom.value = '';
11782 this.setRawValue('');
11783 this.lastSelectionText = '';
11784 this.lastData = false;
11789 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11790 * will be displayed in the field. If the value does not match the data value of an existing item,
11791 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11792 * Otherwise the field will be blank (although the value will still be set).
11793 * @param {String} value The value to match
11795 setValue : function(v){
11802 if(this.valueField){
11803 var r = this.findRecord(this.valueField, v);
11805 text = r.data[this.displayField];
11806 }else if(this.valueNotFoundText !== undefined){
11807 text = this.valueNotFoundText;
11810 this.lastSelectionText = text;
11811 if(this.hiddenField){
11812 this.hiddenField.dom.value = v;
11814 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11818 * @property {Object} the last set data for the element
11823 * Sets the value of the field based on a object which is related to the record format for the store.
11824 * @param {Object} value the value to set as. or false on reset?
11826 setFromData : function(o){
11833 var dv = ''; // display value
11834 var vv = ''; // value value..
11836 if (this.displayField) {
11837 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11839 // this is an error condition!!!
11840 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11843 if(this.valueField){
11844 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11847 if(this.hiddenField){
11848 this.hiddenField.dom.value = vv;
11850 this.lastSelectionText = dv;
11851 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11855 // no hidden field.. - we store the value in 'value', but still display
11856 // display field!!!!
11857 this.lastSelectionText = dv;
11858 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11864 reset : function(){
11865 // overridden so that last data is reset..
11872 this.setValue(this.originalValue);
11873 this.clearInvalid();
11874 this.lastData = false;
11876 this.view.clearSelections();
11880 findRecord : function(prop, value){
11882 if(this.store.getCount() > 0){
11883 this.store.each(function(r){
11884 if(r.data[prop] == value){
11894 getName: function()
11896 // returns hidden if it's set..
11897 if (!this.rendered) {return ''};
11898 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11902 onViewMove : function(e, t){
11903 this.inKeyMode = false;
11907 onViewOver : function(e, t){
11908 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11911 var item = this.view.findItemFromChild(t);
11914 var index = this.view.indexOf(item);
11915 this.select(index, false);
11920 onViewClick : function(view, doFocus, el, e)
11922 var index = this.view.getSelectedIndexes()[0];
11924 var r = this.store.getAt(index);
11928 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11935 Roo.each(this.tickItems, function(v,k){
11937 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11938 _this.tickItems.splice(k, 1);
11940 if(typeof(e) == 'undefined' && view == false){
11941 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11953 this.tickItems.push(r.data);
11955 if(typeof(e) == 'undefined' && view == false){
11956 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11963 this.onSelect(r, index);
11965 if(doFocus !== false && !this.blockFocus){
11966 this.inputEl().focus();
11971 restrictHeight : function(){
11972 //this.innerList.dom.style.height = '';
11973 //var inner = this.innerList.dom;
11974 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11975 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11976 //this.list.beginUpdate();
11977 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11978 this.list.alignTo(this.inputEl(), this.listAlign);
11979 this.list.alignTo(this.inputEl(), this.listAlign);
11980 //this.list.endUpdate();
11984 onEmptyResults : function(){
11986 if(this.tickable && this.editable){
11987 this.restrictHeight();
11995 * Returns true if the dropdown list is expanded, else false.
11997 isExpanded : function(){
11998 return this.list.isVisible();
12002 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12003 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12004 * @param {String} value The data value of the item to select
12005 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12006 * selected item if it is not currently in view (defaults to true)
12007 * @return {Boolean} True if the value matched an item in the list, else false
12009 selectByValue : function(v, scrollIntoView){
12010 if(v !== undefined && v !== null){
12011 var r = this.findRecord(this.valueField || this.displayField, v);
12013 this.select(this.store.indexOf(r), scrollIntoView);
12021 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12022 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12023 * @param {Number} index The zero-based index of the list item to select
12024 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12025 * selected item if it is not currently in view (defaults to true)
12027 select : function(index, scrollIntoView){
12028 this.selectedIndex = index;
12029 this.view.select(index);
12030 if(scrollIntoView !== false){
12031 var el = this.view.getNode(index);
12033 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12036 this.list.scrollChildIntoView(el, false);
12042 selectNext : function(){
12043 var ct = this.store.getCount();
12045 if(this.selectedIndex == -1){
12047 }else if(this.selectedIndex < ct-1){
12048 this.select(this.selectedIndex+1);
12054 selectPrev : function(){
12055 var ct = this.store.getCount();
12057 if(this.selectedIndex == -1){
12059 }else if(this.selectedIndex != 0){
12060 this.select(this.selectedIndex-1);
12066 onKeyUp : function(e){
12067 if(this.editable !== false && !e.isSpecialKey()){
12068 this.lastKey = e.getKey();
12069 this.dqTask.delay(this.queryDelay);
12074 validateBlur : function(){
12075 return !this.list || !this.list.isVisible();
12079 initQuery : function(){
12081 var v = this.getRawValue();
12083 if(this.tickable && this.editable){
12084 v = this.tickableInputEl().getValue();
12091 doForce : function(){
12092 if(this.inputEl().dom.value.length > 0){
12093 this.inputEl().dom.value =
12094 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12100 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12101 * query allowing the query action to be canceled if needed.
12102 * @param {String} query The SQL query to execute
12103 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12104 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12105 * saved in the current store (defaults to false)
12107 doQuery : function(q, forceAll){
12109 if(q === undefined || q === null){
12114 forceAll: forceAll,
12118 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12123 forceAll = qe.forceAll;
12124 if(forceAll === true || (q.length >= this.minChars)){
12126 this.hasQuery = true;
12128 if(this.lastQuery != q || this.alwaysQuery){
12129 this.lastQuery = q;
12130 if(this.mode == 'local'){
12131 this.selectedIndex = -1;
12133 this.store.clearFilter();
12135 this.store.filter(this.filterField || this.displayField, q, this.anyMatch);
12137 if(this.filterSort){
12138 this.store.data.sort(this.displayField, this.filterSortDir);
12145 this.store.baseParams[this.queryParam] = q;
12147 var options = {params : this.getParams(q)};
12150 options.add = true;
12151 options.params.start = this.page * this.pageSize;
12154 this.store.load(options);
12157 * this code will make the page width larger, at the beginning, the list not align correctly,
12158 * we should expand the list on onLoad
12159 * so command out it
12164 this.selectedIndex = -1;
12169 this.loadNext = false;
12173 getParams : function(q){
12175 //p[this.queryParam] = q;
12179 p.limit = this.pageSize;
12185 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12187 collapse : function(){
12188 if(!this.isExpanded()){
12195 this.hasFocus = false;
12197 this.cancelBtn.hide();
12198 this.trigger.show();
12201 this.tickableInputEl().dom.value = '';
12202 this.tickableInputEl().blur();
12207 Roo.get(document).un('mousedown', this.collapseIf, this);
12208 Roo.get(document).un('mousewheel', this.collapseIf, this);
12209 if (!this.editable) {
12210 Roo.get(document).un('keydown', this.listKeyPress, this);
12212 this.fireEvent('collapse', this);
12216 collapseIf : function(e){
12217 var in_combo = e.within(this.el);
12218 var in_list = e.within(this.list);
12219 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12221 if (in_combo || in_list || is_list) {
12222 //e.stopPropagation();
12227 this.onTickableFooterButtonClick(e, false, false);
12235 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12237 expand : function(){
12239 if(this.isExpanded() || !this.hasFocus){
12243 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12244 this.list.setWidth(lw);
12251 this.restrictHeight();
12255 this.tickItems = Roo.apply([], this.item);
12258 this.cancelBtn.show();
12259 this.trigger.hide();
12262 this.tickableInputEl().focus();
12267 Roo.get(document).on('mousedown', this.collapseIf, this);
12268 Roo.get(document).on('mousewheel', this.collapseIf, this);
12269 if (!this.editable) {
12270 Roo.get(document).on('keydown', this.listKeyPress, this);
12273 this.fireEvent('expand', this);
12277 // Implements the default empty TriggerField.onTriggerClick function
12278 onTriggerClick : function(e)
12280 Roo.log('trigger click');
12282 if(this.disabled || !this.triggerList){
12287 this.loadNext = false;
12289 if(this.isExpanded()){
12291 if (!this.blockFocus) {
12292 this.inputEl().focus();
12296 this.hasFocus = true;
12297 if(this.triggerAction == 'all') {
12298 this.doQuery(this.allQuery, true);
12300 this.doQuery(this.getRawValue());
12302 if (!this.blockFocus) {
12303 this.inputEl().focus();
12308 onTickableTriggerClick : function(e)
12315 this.loadNext = false;
12316 this.hasFocus = true;
12318 if(this.triggerAction == 'all') {
12319 this.doQuery(this.allQuery, true);
12321 this.doQuery(this.getRawValue());
12325 onSearchFieldClick : function(e)
12327 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12328 this.onTickableFooterButtonClick(e, false, false);
12332 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12337 this.loadNext = false;
12338 this.hasFocus = true;
12340 if(this.triggerAction == 'all') {
12341 this.doQuery(this.allQuery, true);
12343 this.doQuery(this.getRawValue());
12347 listKeyPress : function(e)
12349 //Roo.log('listkeypress');
12350 // scroll to first matching element based on key pres..
12351 if (e.isSpecialKey()) {
12354 var k = String.fromCharCode(e.getKey()).toUpperCase();
12357 var csel = this.view.getSelectedNodes();
12358 var cselitem = false;
12360 var ix = this.view.indexOf(csel[0]);
12361 cselitem = this.store.getAt(ix);
12362 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12368 this.store.each(function(v) {
12370 // start at existing selection.
12371 if (cselitem.id == v.id) {
12377 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12378 match = this.store.indexOf(v);
12384 if (match === false) {
12385 return true; // no more action?
12388 this.view.select(match);
12389 var sn = Roo.get(this.view.getSelectedNodes()[0])
12390 sn.scrollIntoView(sn.dom.parentNode, false);
12393 onViewScroll : function(e, t){
12395 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){
12399 this.hasQuery = true;
12401 this.loading = this.list.select('.loading', true).first();
12403 if(this.loading === null){
12404 this.list.createChild({
12406 cls: 'loading select2-more-results select2-active',
12407 html: 'Loading more results...'
12410 this.loading = this.list.select('.loading', true).first();
12412 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12414 this.loading.hide();
12417 this.loading.show();
12422 this.loadNext = true;
12424 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12429 addItem : function(o)
12431 var dv = ''; // display value
12433 if (this.displayField) {
12434 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12436 // this is an error condition!!!
12437 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12444 var choice = this.choices.createChild({
12446 cls: 'select2-search-choice',
12455 cls: 'select2-search-choice-close',
12460 }, this.searchField);
12462 var close = choice.select('a.select2-search-choice-close', true).first()
12464 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12472 this.inputEl().dom.value = '';
12477 onRemoveItem : function(e, _self, o)
12479 e.preventDefault();
12481 this.lastItem = Roo.apply([], this.item);
12483 var index = this.item.indexOf(o.data) * 1;
12486 Roo.log('not this item?!');
12490 this.item.splice(index, 1);
12495 this.fireEvent('remove', this, e);
12501 syncValue : function()
12503 if(!this.item.length){
12510 Roo.each(this.item, function(i){
12511 if(_this.valueField){
12512 value.push(i[_this.valueField]);
12519 this.value = value.join(',');
12521 if(this.hiddenField){
12522 this.hiddenField.dom.value = this.value;
12526 clearItem : function()
12528 if(!this.multiple){
12534 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12543 inputEl: function ()
12546 return this.searchField;
12548 return this.el.select('input.form-control',true).first();
12552 onTickableFooterButtonClick : function(e, btn, el)
12554 e.preventDefault();
12556 this.lastItem = Roo.apply([], this.item);
12558 if(btn && btn.name == 'cancel'){
12559 this.tickItems = Roo.apply([], this.item);
12568 Roo.each(this.tickItems, function(o){
12576 validate : function()
12578 var v = this.getRawValue();
12581 v = this.getValue();
12584 if(this.disabled || this.allowBlank || v.length){
12589 this.markInvalid();
12593 tickableInputEl : function()
12595 if(!this.tickable || !this.editable){
12596 return this.inputEl();
12599 return this.inputEl().select('.select2-search-field-input', true).first();
12605 * @cfg {Boolean} grow
12609 * @cfg {Number} growMin
12613 * @cfg {Number} growMax
12623 * Ext JS Library 1.1.1
12624 * Copyright(c) 2006-2007, Ext JS, LLC.
12626 * Originally Released Under LGPL - original licence link has changed is not relivant.
12629 * <script type="text/javascript">
12634 * @extends Roo.util.Observable
12635 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12636 * This class also supports single and multi selection modes. <br>
12637 * Create a data model bound view:
12639 var store = new Roo.data.Store(...);
12641 var view = new Roo.View({
12643 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12645 singleSelect: true,
12646 selectedClass: "ydataview-selected",
12650 // listen for node click?
12651 view.on("click", function(vw, index, node, e){
12652 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12656 dataModel.load("foobar.xml");
12658 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12660 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12661 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12663 * Note: old style constructor is still suported (container, template, config)
12666 * Create a new View
12667 * @param {Object} config The config object
12670 Roo.View = function(config, depreciated_tpl, depreciated_config){
12672 this.parent = false;
12674 if (typeof(depreciated_tpl) == 'undefined') {
12675 // new way.. - universal constructor.
12676 Roo.apply(this, config);
12677 this.el = Roo.get(this.el);
12680 this.el = Roo.get(config);
12681 this.tpl = depreciated_tpl;
12682 Roo.apply(this, depreciated_config);
12684 this.wrapEl = this.el.wrap().wrap();
12685 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12688 if(typeof(this.tpl) == "string"){
12689 this.tpl = new Roo.Template(this.tpl);
12691 // support xtype ctors..
12692 this.tpl = new Roo.factory(this.tpl, Roo);
12696 this.tpl.compile();
12701 * @event beforeclick
12702 * Fires before a click is processed. Returns false to cancel the default action.
12703 * @param {Roo.View} this
12704 * @param {Number} index The index of the target node
12705 * @param {HTMLElement} node The target node
12706 * @param {Roo.EventObject} e The raw event object
12708 "beforeclick" : true,
12711 * Fires when a template node is clicked.
12712 * @param {Roo.View} this
12713 * @param {Number} index The index of the target node
12714 * @param {HTMLElement} node The target node
12715 * @param {Roo.EventObject} e The raw event object
12720 * Fires when a template node is double clicked.
12721 * @param {Roo.View} this
12722 * @param {Number} index The index of the target node
12723 * @param {HTMLElement} node The target node
12724 * @param {Roo.EventObject} e The raw event object
12728 * @event contextmenu
12729 * Fires when a template node is right clicked.
12730 * @param {Roo.View} this
12731 * @param {Number} index The index of the target node
12732 * @param {HTMLElement} node The target node
12733 * @param {Roo.EventObject} e The raw event object
12735 "contextmenu" : true,
12737 * @event selectionchange
12738 * Fires when the selected nodes change.
12739 * @param {Roo.View} this
12740 * @param {Array} selections Array of the selected nodes
12742 "selectionchange" : true,
12745 * @event beforeselect
12746 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12747 * @param {Roo.View} this
12748 * @param {HTMLElement} node The node to be selected
12749 * @param {Array} selections Array of currently selected nodes
12751 "beforeselect" : true,
12753 * @event preparedata
12754 * Fires on every row to render, to allow you to change the data.
12755 * @param {Roo.View} this
12756 * @param {Object} data to be rendered (change this)
12758 "preparedata" : true
12766 "click": this.onClick,
12767 "dblclick": this.onDblClick,
12768 "contextmenu": this.onContextMenu,
12772 this.selections = [];
12774 this.cmp = new Roo.CompositeElementLite([]);
12776 this.store = Roo.factory(this.store, Roo.data);
12777 this.setStore(this.store, true);
12780 if ( this.footer && this.footer.xtype) {
12782 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12784 this.footer.dataSource = this.store
12785 this.footer.container = fctr;
12786 this.footer = Roo.factory(this.footer, Roo);
12787 fctr.insertFirst(this.el);
12789 // this is a bit insane - as the paging toolbar seems to detach the el..
12790 // dom.parentNode.parentNode.parentNode
12791 // they get detached?
12795 Roo.View.superclass.constructor.call(this);
12800 Roo.extend(Roo.View, Roo.util.Observable, {
12803 * @cfg {Roo.data.Store} store Data store to load data from.
12808 * @cfg {String|Roo.Element} el The container element.
12813 * @cfg {String|Roo.Template} tpl The template used by this View
12817 * @cfg {String} dataName the named area of the template to use as the data area
12818 * Works with domtemplates roo-name="name"
12822 * @cfg {String} selectedClass The css class to add to selected nodes
12824 selectedClass : "x-view-selected",
12826 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12831 * @cfg {String} text to display on mask (default Loading)
12835 * @cfg {Boolean} multiSelect Allow multiple selection
12837 multiSelect : false,
12839 * @cfg {Boolean} singleSelect Allow single selection
12841 singleSelect: false,
12844 * @cfg {Boolean} toggleSelect - selecting
12846 toggleSelect : false,
12849 * @cfg {Boolean} tickable - selecting
12854 * Returns the element this view is bound to.
12855 * @return {Roo.Element}
12857 getEl : function(){
12858 return this.wrapEl;
12864 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12866 refresh : function(){
12867 //Roo.log('refresh');
12870 // if we are using something like 'domtemplate', then
12871 // the what gets used is:
12872 // t.applySubtemplate(NAME, data, wrapping data..)
12873 // the outer template then get' applied with
12874 // the store 'extra data'
12875 // and the body get's added to the
12876 // roo-name="data" node?
12877 // <span class='roo-tpl-{name}'></span> ?????
12881 this.clearSelections();
12882 this.el.update("");
12884 var records = this.store.getRange();
12885 if(records.length < 1) {
12887 // is this valid?? = should it render a template??
12889 this.el.update(this.emptyText);
12893 if (this.dataName) {
12894 this.el.update(t.apply(this.store.meta)); //????
12895 el = this.el.child('.roo-tpl-' + this.dataName);
12898 for(var i = 0, len = records.length; i < len; i++){
12899 var data = this.prepareData(records[i].data, i, records[i]);
12900 this.fireEvent("preparedata", this, data, i, records[i]);
12902 var d = Roo.apply({}, data);
12905 Roo.apply(d, {'roo-id' : Roo.id()});
12909 Roo.each(this.parent.item, function(item){
12910 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12913 Roo.apply(d, {'roo-data-checked' : 'checked'});
12917 html[html.length] = Roo.util.Format.trim(
12919 t.applySubtemplate(this.dataName, d, this.store.meta) :
12926 el.update(html.join(""));
12927 this.nodes = el.dom.childNodes;
12928 this.updateIndexes(0);
12933 * Function to override to reformat the data that is sent to
12934 * the template for each node.
12935 * DEPRICATED - use the preparedata event handler.
12936 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12937 * a JSON object for an UpdateManager bound view).
12939 prepareData : function(data, index, record)
12941 this.fireEvent("preparedata", this, data, index, record);
12945 onUpdate : function(ds, record){
12946 // Roo.log('on update');
12947 this.clearSelections();
12948 var index = this.store.indexOf(record);
12949 var n = this.nodes[index];
12950 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12951 n.parentNode.removeChild(n);
12952 this.updateIndexes(index, index);
12958 onAdd : function(ds, records, index)
12960 //Roo.log(['on Add', ds, records, index] );
12961 this.clearSelections();
12962 if(this.nodes.length == 0){
12966 var n = this.nodes[index];
12967 for(var i = 0, len = records.length; i < len; i++){
12968 var d = this.prepareData(records[i].data, i, records[i]);
12970 this.tpl.insertBefore(n, d);
12973 this.tpl.append(this.el, d);
12976 this.updateIndexes(index);
12979 onRemove : function(ds, record, index){
12980 // Roo.log('onRemove');
12981 this.clearSelections();
12982 var el = this.dataName ?
12983 this.el.child('.roo-tpl-' + this.dataName) :
12986 el.dom.removeChild(this.nodes[index]);
12987 this.updateIndexes(index);
12991 * Refresh an individual node.
12992 * @param {Number} index
12994 refreshNode : function(index){
12995 this.onUpdate(this.store, this.store.getAt(index));
12998 updateIndexes : function(startIndex, endIndex){
12999 var ns = this.nodes;
13000 startIndex = startIndex || 0;
13001 endIndex = endIndex || ns.length - 1;
13002 for(var i = startIndex; i <= endIndex; i++){
13003 ns[i].nodeIndex = i;
13008 * Changes the data store this view uses and refresh the view.
13009 * @param {Store} store
13011 setStore : function(store, initial){
13012 if(!initial && this.store){
13013 this.store.un("datachanged", this.refresh);
13014 this.store.un("add", this.onAdd);
13015 this.store.un("remove", this.onRemove);
13016 this.store.un("update", this.onUpdate);
13017 this.store.un("clear", this.refresh);
13018 this.store.un("beforeload", this.onBeforeLoad);
13019 this.store.un("load", this.onLoad);
13020 this.store.un("loadexception", this.onLoad);
13024 store.on("datachanged", this.refresh, this);
13025 store.on("add", this.onAdd, this);
13026 store.on("remove", this.onRemove, this);
13027 store.on("update", this.onUpdate, this);
13028 store.on("clear", this.refresh, this);
13029 store.on("beforeload", this.onBeforeLoad, this);
13030 store.on("load", this.onLoad, this);
13031 store.on("loadexception", this.onLoad, this);
13039 * onbeforeLoad - masks the loading area.
13042 onBeforeLoad : function(store,opts)
13044 //Roo.log('onBeforeLoad');
13046 this.el.update("");
13048 this.el.mask(this.mask ? this.mask : "Loading" );
13050 onLoad : function ()
13057 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13058 * @param {HTMLElement} node
13059 * @return {HTMLElement} The template node
13061 findItemFromChild : function(node){
13062 var el = this.dataName ?
13063 this.el.child('.roo-tpl-' + this.dataName,true) :
13066 if(!node || node.parentNode == el){
13069 var p = node.parentNode;
13070 while(p && p != el){
13071 if(p.parentNode == el){
13080 onClick : function(e){
13081 var item = this.findItemFromChild(e.getTarget());
13083 var index = this.indexOf(item);
13084 if(this.onItemClick(item, index, e) !== false){
13085 this.fireEvent("click", this, index, item, e);
13088 this.clearSelections();
13093 onContextMenu : function(e){
13094 var item = this.findItemFromChild(e.getTarget());
13096 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13101 onDblClick : function(e){
13102 var item = this.findItemFromChild(e.getTarget());
13104 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13108 onItemClick : function(item, index, e)
13110 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13113 if (this.toggleSelect) {
13114 var m = this.isSelected(item) ? 'unselect' : 'select';
13117 _t[m](item, true, false);
13120 if(this.multiSelect || this.singleSelect){
13121 if(this.multiSelect && e.shiftKey && this.lastSelection){
13122 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13124 this.select(item, this.multiSelect && e.ctrlKey);
13125 this.lastSelection = item;
13128 if(!this.tickable){
13129 e.preventDefault();
13137 * Get the number of selected nodes.
13140 getSelectionCount : function(){
13141 return this.selections.length;
13145 * Get the currently selected nodes.
13146 * @return {Array} An array of HTMLElements
13148 getSelectedNodes : function(){
13149 return this.selections;
13153 * Get the indexes of the selected nodes.
13156 getSelectedIndexes : function(){
13157 var indexes = [], s = this.selections;
13158 for(var i = 0, len = s.length; i < len; i++){
13159 indexes.push(s[i].nodeIndex);
13165 * Clear all selections
13166 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13168 clearSelections : function(suppressEvent){
13169 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13170 this.cmp.elements = this.selections;
13171 this.cmp.removeClass(this.selectedClass);
13172 this.selections = [];
13173 if(!suppressEvent){
13174 this.fireEvent("selectionchange", this, this.selections);
13180 * Returns true if the passed node is selected
13181 * @param {HTMLElement/Number} node The node or node index
13182 * @return {Boolean}
13184 isSelected : function(node){
13185 var s = this.selections;
13189 node = this.getNode(node);
13190 return s.indexOf(node) !== -1;
13195 * @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
13196 * @param {Boolean} keepExisting (optional) true to keep existing selections
13197 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13199 select : function(nodeInfo, keepExisting, suppressEvent){
13200 if(nodeInfo instanceof Array){
13202 this.clearSelections(true);
13204 for(var i = 0, len = nodeInfo.length; i < len; i++){
13205 this.select(nodeInfo[i], true, true);
13209 var node = this.getNode(nodeInfo);
13210 if(!node || this.isSelected(node)){
13211 return; // already selected.
13214 this.clearSelections(true);
13217 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13218 Roo.fly(node).addClass(this.selectedClass);
13219 this.selections.push(node);
13220 if(!suppressEvent){
13221 this.fireEvent("selectionchange", this, this.selections);
13229 * @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
13230 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13231 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13233 unselect : function(nodeInfo, keepExisting, suppressEvent)
13235 if(nodeInfo instanceof Array){
13236 Roo.each(this.selections, function(s) {
13237 this.unselect(s, nodeInfo);
13241 var node = this.getNode(nodeInfo);
13242 if(!node || !this.isSelected(node)){
13243 //Roo.log("not selected");
13244 return; // not selected.
13248 Roo.each(this.selections, function(s) {
13250 Roo.fly(node).removeClass(this.selectedClass);
13257 this.selections= ns;
13258 this.fireEvent("selectionchange", this, this.selections);
13262 * Gets a template node.
13263 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13264 * @return {HTMLElement} The node or null if it wasn't found
13266 getNode : function(nodeInfo){
13267 if(typeof nodeInfo == "string"){
13268 return document.getElementById(nodeInfo);
13269 }else if(typeof nodeInfo == "number"){
13270 return this.nodes[nodeInfo];
13276 * Gets a range template nodes.
13277 * @param {Number} startIndex
13278 * @param {Number} endIndex
13279 * @return {Array} An array of nodes
13281 getNodes : function(start, end){
13282 var ns = this.nodes;
13283 start = start || 0;
13284 end = typeof end == "undefined" ? ns.length - 1 : end;
13287 for(var i = start; i <= end; i++){
13291 for(var i = start; i >= end; i--){
13299 * Finds the index of the passed node
13300 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13301 * @return {Number} The index of the node or -1
13303 indexOf : function(node){
13304 node = this.getNode(node);
13305 if(typeof node.nodeIndex == "number"){
13306 return node.nodeIndex;
13308 var ns = this.nodes;
13309 for(var i = 0, len = ns.length; i < len; i++){
13320 * based on jquery fullcalendar
13324 Roo.bootstrap = Roo.bootstrap || {};
13326 * @class Roo.bootstrap.Calendar
13327 * @extends Roo.bootstrap.Component
13328 * Bootstrap Calendar class
13329 * @cfg {Boolean} loadMask (true|false) default false
13330 * @cfg {Object} header generate the user specific header of the calendar, default false
13333 * Create a new Container
13334 * @param {Object} config The config object
13339 Roo.bootstrap.Calendar = function(config){
13340 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13344 * Fires when a date is selected
13345 * @param {DatePicker} this
13346 * @param {Date} date The selected date
13350 * @event monthchange
13351 * Fires when the displayed month changes
13352 * @param {DatePicker} this
13353 * @param {Date} date The selected month
13355 'monthchange': true,
13357 * @event evententer
13358 * Fires when mouse over an event
13359 * @param {Calendar} this
13360 * @param {event} Event
13362 'evententer': true,
13364 * @event eventleave
13365 * Fires when the mouse leaves an
13366 * @param {Calendar} this
13369 'eventleave': true,
13371 * @event eventclick
13372 * Fires when the mouse click an
13373 * @param {Calendar} this
13382 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13385 * @cfg {Number} startDay
13386 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13394 getAutoCreate : function(){
13397 var fc_button = function(name, corner, style, content ) {
13398 return Roo.apply({},{
13400 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13402 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13405 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13416 style : 'width:100%',
13423 cls : 'fc-header-left',
13425 fc_button('prev', 'left', 'arrow', '‹' ),
13426 fc_button('next', 'right', 'arrow', '›' ),
13427 { tag: 'span', cls: 'fc-header-space' },
13428 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13436 cls : 'fc-header-center',
13440 cls: 'fc-header-title',
13443 html : 'month / year'
13451 cls : 'fc-header-right',
13453 /* fc_button('month', 'left', '', 'month' ),
13454 fc_button('week', '', '', 'week' ),
13455 fc_button('day', 'right', '', 'day' )
13467 header = this.header;
13470 var cal_heads = function() {
13472 // fixme - handle this.
13474 for (var i =0; i < Date.dayNames.length; i++) {
13475 var d = Date.dayNames[i];
13478 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13479 html : d.substring(0,3)
13483 ret[0].cls += ' fc-first';
13484 ret[6].cls += ' fc-last';
13487 var cal_cell = function(n) {
13490 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13495 cls: 'fc-day-number',
13499 cls: 'fc-day-content',
13503 style: 'position: relative;' // height: 17px;
13515 var cal_rows = function() {
13518 for (var r = 0; r < 6; r++) {
13525 for (var i =0; i < Date.dayNames.length; i++) {
13526 var d = Date.dayNames[i];
13527 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13530 row.cn[0].cls+=' fc-first';
13531 row.cn[0].cn[0].style = 'min-height:90px';
13532 row.cn[6].cls+=' fc-last';
13536 ret[0].cls += ' fc-first';
13537 ret[4].cls += ' fc-prev-last';
13538 ret[5].cls += ' fc-last';
13545 cls: 'fc-border-separate',
13546 style : 'width:100%',
13554 cls : 'fc-first fc-last',
13572 cls : 'fc-content',
13573 style : "position: relative;",
13576 cls : 'fc-view fc-view-month fc-grid',
13577 style : 'position: relative',
13578 unselectable : 'on',
13581 cls : 'fc-event-container',
13582 style : 'position:absolute;z-index:8;top:0;left:0;'
13600 initEvents : function()
13603 throw "can not find store for calendar";
13609 style: "text-align:center",
13613 style: "background-color:white;width:50%;margin:250 auto",
13617 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13628 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13630 var size = this.el.select('.fc-content', true).first().getSize();
13631 this.maskEl.setSize(size.width, size.height);
13632 this.maskEl.enableDisplayMode("block");
13633 if(!this.loadMask){
13634 this.maskEl.hide();
13637 this.store = Roo.factory(this.store, Roo.data);
13638 this.store.on('load', this.onLoad, this);
13639 this.store.on('beforeload', this.onBeforeLoad, this);
13643 this.cells = this.el.select('.fc-day',true);
13644 //Roo.log(this.cells);
13645 this.textNodes = this.el.query('.fc-day-number');
13646 this.cells.addClassOnOver('fc-state-hover');
13648 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13649 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13650 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13651 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13653 this.on('monthchange', this.onMonthChange, this);
13655 this.update(new Date().clearTime());
13658 resize : function() {
13659 var sz = this.el.getSize();
13661 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13662 this.el.select('.fc-day-content div',true).setHeight(34);
13667 showPrevMonth : function(e){
13668 this.update(this.activeDate.add("mo", -1));
13670 showToday : function(e){
13671 this.update(new Date().clearTime());
13674 showNextMonth : function(e){
13675 this.update(this.activeDate.add("mo", 1));
13679 showPrevYear : function(){
13680 this.update(this.activeDate.add("y", -1));
13684 showNextYear : function(){
13685 this.update(this.activeDate.add("y", 1));
13690 update : function(date)
13692 var vd = this.activeDate;
13693 this.activeDate = date;
13694 // if(vd && this.el){
13695 // var t = date.getTime();
13696 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13697 // Roo.log('using add remove');
13699 // this.fireEvent('monthchange', this, date);
13701 // this.cells.removeClass("fc-state-highlight");
13702 // this.cells.each(function(c){
13703 // if(c.dateValue == t){
13704 // c.addClass("fc-state-highlight");
13705 // setTimeout(function(){
13706 // try{c.dom.firstChild.focus();}catch(e){}
13716 var days = date.getDaysInMonth();
13718 var firstOfMonth = date.getFirstDateOfMonth();
13719 var startingPos = firstOfMonth.getDay()-this.startDay;
13721 if(startingPos < this.startDay){
13725 var pm = date.add(Date.MONTH, -1);
13726 var prevStart = pm.getDaysInMonth()-startingPos;
13728 this.cells = this.el.select('.fc-day',true);
13729 this.textNodes = this.el.query('.fc-day-number');
13730 this.cells.addClassOnOver('fc-state-hover');
13732 var cells = this.cells.elements;
13733 var textEls = this.textNodes;
13735 Roo.each(cells, function(cell){
13736 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13739 days += startingPos;
13741 // convert everything to numbers so it's fast
13742 var day = 86400000;
13743 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13746 //Roo.log(prevStart);
13748 var today = new Date().clearTime().getTime();
13749 var sel = date.clearTime().getTime();
13750 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13751 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13752 var ddMatch = this.disabledDatesRE;
13753 var ddText = this.disabledDatesText;
13754 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13755 var ddaysText = this.disabledDaysText;
13756 var format = this.format;
13758 var setCellClass = function(cal, cell){
13762 //Roo.log('set Cell Class');
13764 var t = d.getTime();
13768 cell.dateValue = t;
13770 cell.className += " fc-today";
13771 cell.className += " fc-state-highlight";
13772 cell.title = cal.todayText;
13775 // disable highlight in other month..
13776 //cell.className += " fc-state-highlight";
13781 cell.className = " fc-state-disabled";
13782 cell.title = cal.minText;
13786 cell.className = " fc-state-disabled";
13787 cell.title = cal.maxText;
13791 if(ddays.indexOf(d.getDay()) != -1){
13792 cell.title = ddaysText;
13793 cell.className = " fc-state-disabled";
13796 if(ddMatch && format){
13797 var fvalue = d.dateFormat(format);
13798 if(ddMatch.test(fvalue)){
13799 cell.title = ddText.replace("%0", fvalue);
13800 cell.className = " fc-state-disabled";
13804 if (!cell.initialClassName) {
13805 cell.initialClassName = cell.dom.className;
13808 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13813 for(; i < startingPos; i++) {
13814 textEls[i].innerHTML = (++prevStart);
13815 d.setDate(d.getDate()+1);
13817 cells[i].className = "fc-past fc-other-month";
13818 setCellClass(this, cells[i]);
13823 for(; i < days; i++){
13824 intDay = i - startingPos + 1;
13825 textEls[i].innerHTML = (intDay);
13826 d.setDate(d.getDate()+1);
13828 cells[i].className = ''; // "x-date-active";
13829 setCellClass(this, cells[i]);
13833 for(; i < 42; i++) {
13834 textEls[i].innerHTML = (++extraDays);
13835 d.setDate(d.getDate()+1);
13837 cells[i].className = "fc-future fc-other-month";
13838 setCellClass(this, cells[i]);
13841 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13843 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13845 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13846 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13848 if(totalRows != 6){
13849 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13850 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13853 this.fireEvent('monthchange', this, date);
13857 if(!this.internalRender){
13858 var main = this.el.dom.firstChild;
13859 var w = main.offsetWidth;
13860 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13861 Roo.fly(main).setWidth(w);
13862 this.internalRender = true;
13863 // opera does not respect the auto grow header center column
13864 // then, after it gets a width opera refuses to recalculate
13865 // without a second pass
13866 if(Roo.isOpera && !this.secondPass){
13867 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13868 this.secondPass = true;
13869 this.update.defer(10, this, [date]);
13876 findCell : function(dt) {
13877 dt = dt.clearTime().getTime();
13879 this.cells.each(function(c){
13880 //Roo.log("check " +c.dateValue + '?=' + dt);
13881 if(c.dateValue == dt){
13891 findCells : function(ev) {
13892 var s = ev.start.clone().clearTime().getTime();
13894 var e= ev.end.clone().clearTime().getTime();
13897 this.cells.each(function(c){
13898 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13900 if(c.dateValue > e){
13903 if(c.dateValue < s){
13912 // findBestRow: function(cells)
13916 // for (var i =0 ; i < cells.length;i++) {
13917 // ret = Math.max(cells[i].rows || 0,ret);
13924 addItem : function(ev)
13926 // look for vertical location slot in
13927 var cells = this.findCells(ev);
13929 // ev.row = this.findBestRow(cells);
13931 // work out the location.
13935 for(var i =0; i < cells.length; i++) {
13937 cells[i].row = cells[0].row;
13940 cells[i].row = cells[i].row + 1;
13950 if (crow.start.getY() == cells[i].getY()) {
13952 crow.end = cells[i];
13969 cells[0].events.push(ev);
13971 this.calevents.push(ev);
13974 clearEvents: function() {
13976 if(!this.calevents){
13980 Roo.each(this.cells.elements, function(c){
13986 Roo.each(this.calevents, function(e) {
13987 Roo.each(e.els, function(el) {
13988 el.un('mouseenter' ,this.onEventEnter, this);
13989 el.un('mouseleave' ,this.onEventLeave, this);
13994 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14000 renderEvents: function()
14004 this.cells.each(function(c) {
14013 if(c.row != c.events.length){
14014 r = 4 - (4 - (c.row - c.events.length));
14017 c.events = ev.slice(0, r);
14018 c.more = ev.slice(r);
14020 if(c.more.length && c.more.length == 1){
14021 c.events.push(c.more.pop());
14024 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14028 this.cells.each(function(c) {
14030 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14033 for (var e = 0; e < c.events.length; e++){
14034 var ev = c.events[e];
14035 var rows = ev.rows;
14037 for(var i = 0; i < rows.length; i++) {
14039 // how many rows should it span..
14042 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14043 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14045 unselectable : "on",
14048 cls: 'fc-event-inner',
14052 // cls: 'fc-event-time',
14053 // html : cells.length > 1 ? '' : ev.time
14057 cls: 'fc-event-title',
14058 html : String.format('{0}', ev.title)
14065 cls: 'ui-resizable-handle ui-resizable-e',
14066 html : '  '
14073 cfg.cls += ' fc-event-start';
14075 if ((i+1) == rows.length) {
14076 cfg.cls += ' fc-event-end';
14079 var ctr = _this.el.select('.fc-event-container',true).first();
14080 var cg = ctr.createChild(cfg);
14082 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14083 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14085 var r = (c.more.length) ? 1 : 0;
14086 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14087 cg.setWidth(ebox.right - sbox.x -2);
14089 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14090 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14091 cg.on('click', _this.onEventClick, _this, ev);
14102 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14103 style : 'position: absolute',
14104 unselectable : "on",
14107 cls: 'fc-event-inner',
14111 cls: 'fc-event-title',
14119 cls: 'ui-resizable-handle ui-resizable-e',
14120 html : '  '
14126 var ctr = _this.el.select('.fc-event-container',true).first();
14127 var cg = ctr.createChild(cfg);
14129 var sbox = c.select('.fc-day-content',true).first().getBox();
14130 var ebox = c.select('.fc-day-content',true).first().getBox();
14132 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14133 cg.setWidth(ebox.right - sbox.x -2);
14135 cg.on('click', _this.onMoreEventClick, _this, c.more);
14145 onEventEnter: function (e, el,event,d) {
14146 this.fireEvent('evententer', this, el, event);
14149 onEventLeave: function (e, el,event,d) {
14150 this.fireEvent('eventleave', this, el, event);
14153 onEventClick: function (e, el,event,d) {
14154 this.fireEvent('eventclick', this, el, event);
14157 onMonthChange: function () {
14161 onMoreEventClick: function(e, el, more)
14165 this.calpopover.placement = 'right';
14166 this.calpopover.setTitle('More');
14168 this.calpopover.setContent('');
14170 var ctr = this.calpopover.el.select('.popover-content', true).first();
14172 Roo.each(more, function(m){
14174 cls : 'fc-event-hori fc-event-draggable',
14177 var cg = ctr.createChild(cfg);
14179 cg.on('click', _this.onEventClick, _this, m);
14182 this.calpopover.show(el);
14187 onLoad: function ()
14189 this.calevents = [];
14192 if(this.store.getCount() > 0){
14193 this.store.data.each(function(d){
14196 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14197 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14198 time : d.data.start_time,
14199 title : d.data.title,
14200 description : d.data.description,
14201 venue : d.data.venue
14206 this.renderEvents();
14208 if(this.calevents.length && this.loadMask){
14209 this.maskEl.hide();
14213 onBeforeLoad: function()
14215 this.clearEvents();
14217 this.maskEl.show();
14231 * @class Roo.bootstrap.Popover
14232 * @extends Roo.bootstrap.Component
14233 * Bootstrap Popover class
14234 * @cfg {String} html contents of the popover (or false to use children..)
14235 * @cfg {String} title of popover (or false to hide)
14236 * @cfg {String} placement how it is placed
14237 * @cfg {String} trigger click || hover (or false to trigger manually)
14238 * @cfg {String} over what (parent or false to trigger manually.)
14239 * @cfg {Number} delay - delay before showing
14242 * Create a new Popover
14243 * @param {Object} config The config object
14246 Roo.bootstrap.Popover = function(config){
14247 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14250 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14252 title: 'Fill in a title',
14255 placement : 'right',
14256 trigger : 'hover', // hover
14262 can_build_overlaid : false,
14264 getChildContainer : function()
14266 return this.el.select('.popover-content',true).first();
14269 getAutoCreate : function(){
14270 Roo.log('make popover?');
14272 cls : 'popover roo-dynamic',
14273 style: 'display:block',
14279 cls : 'popover-inner',
14283 cls: 'popover-title',
14287 cls : 'popover-content',
14298 setTitle: function(str)
14300 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14302 setContent: function(str)
14304 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14306 // as it get's added to the bottom of the page.
14307 onRender : function(ct, position)
14309 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14311 var cfg = Roo.apply({}, this.getAutoCreate());
14315 cfg.cls += ' ' + this.cls;
14318 cfg.style = this.style;
14320 Roo.log("adding to ")
14321 this.el = Roo.get(document.body).createChild(cfg, position);
14327 initEvents : function()
14329 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14330 this.el.enableDisplayMode('block');
14332 if (this.over === false) {
14335 if (this.triggers === false) {
14338 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14339 var triggers = this.trigger ? this.trigger.split(' ') : [];
14340 Roo.each(triggers, function(trigger) {
14342 if (trigger == 'click') {
14343 on_el.on('click', this.toggle, this);
14344 } else if (trigger != 'manual') {
14345 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14346 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14348 on_el.on(eventIn ,this.enter, this);
14349 on_el.on(eventOut, this.leave, this);
14360 toggle : function () {
14361 this.hoverState == 'in' ? this.leave() : this.enter();
14364 enter : function () {
14367 clearTimeout(this.timeout);
14369 this.hoverState = 'in';
14371 if (!this.delay || !this.delay.show) {
14376 this.timeout = setTimeout(function () {
14377 if (_t.hoverState == 'in') {
14380 }, this.delay.show)
14382 leave : function() {
14383 clearTimeout(this.timeout);
14385 this.hoverState = 'out';
14387 if (!this.delay || !this.delay.hide) {
14392 this.timeout = setTimeout(function () {
14393 if (_t.hoverState == 'out') {
14396 }, this.delay.hide)
14399 show : function (on_el)
14402 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14405 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14406 if (this.html !== false) {
14407 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14409 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14410 if (!this.title.length) {
14411 this.el.select('.popover-title',true).hide();
14414 var placement = typeof this.placement == 'function' ?
14415 this.placement.call(this, this.el, on_el) :
14418 var autoToken = /\s?auto?\s?/i;
14419 var autoPlace = autoToken.test(placement);
14421 placement = placement.replace(autoToken, '') || 'top';
14425 //this.el.setXY([0,0]);
14427 this.el.dom.style.display='block';
14428 this.el.addClass(placement);
14430 //this.el.appendTo(on_el);
14432 var p = this.getPosition();
14433 var box = this.el.getBox();
14438 var align = Roo.bootstrap.Popover.alignment[placement];
14439 this.el.alignTo(on_el, align[0],align[1]);
14440 //var arrow = this.el.select('.arrow',true).first();
14441 //arrow.set(align[2],
14443 this.el.addClass('in');
14444 this.hoverState = null;
14446 if (this.el.hasClass('fade')) {
14453 this.el.setXY([0,0]);
14454 this.el.removeClass('in');
14461 Roo.bootstrap.Popover.alignment = {
14462 'left' : ['r-l', [-10,0], 'right'],
14463 'right' : ['l-r', [10,0], 'left'],
14464 'bottom' : ['t-b', [0,10], 'top'],
14465 'top' : [ 'b-t', [0,-10], 'bottom']
14476 * @class Roo.bootstrap.Progress
14477 * @extends Roo.bootstrap.Component
14478 * Bootstrap Progress class
14479 * @cfg {Boolean} striped striped of the progress bar
14480 * @cfg {Boolean} active animated of the progress bar
14484 * Create a new Progress
14485 * @param {Object} config The config object
14488 Roo.bootstrap.Progress = function(config){
14489 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14492 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14497 getAutoCreate : function(){
14505 cfg.cls += ' progress-striped';
14509 cfg.cls += ' active';
14528 * @class Roo.bootstrap.ProgressBar
14529 * @extends Roo.bootstrap.Component
14530 * Bootstrap ProgressBar class
14531 * @cfg {Number} aria_valuenow aria-value now
14532 * @cfg {Number} aria_valuemin aria-value min
14533 * @cfg {Number} aria_valuemax aria-value max
14534 * @cfg {String} label label for the progress bar
14535 * @cfg {String} panel (success | info | warning | danger )
14536 * @cfg {String} role role of the progress bar
14537 * @cfg {String} sr_only text
14541 * Create a new ProgressBar
14542 * @param {Object} config The config object
14545 Roo.bootstrap.ProgressBar = function(config){
14546 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14549 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14553 aria_valuemax : 100,
14559 getAutoCreate : function()
14564 cls: 'progress-bar',
14565 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14577 cfg.role = this.role;
14580 if(this.aria_valuenow){
14581 cfg['aria-valuenow'] = this.aria_valuenow;
14584 if(this.aria_valuemin){
14585 cfg['aria-valuemin'] = this.aria_valuemin;
14588 if(this.aria_valuemax){
14589 cfg['aria-valuemax'] = this.aria_valuemax;
14592 if(this.label && !this.sr_only){
14593 cfg.html = this.label;
14597 cfg.cls += ' progress-bar-' + this.panel;
14603 update : function(aria_valuenow)
14605 this.aria_valuenow = aria_valuenow;
14607 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14622 * @class Roo.bootstrap.TabGroup
14623 * @extends Roo.bootstrap.Column
14624 * Bootstrap Column class
14625 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14626 * @cfg {Boolean} carousel true to make the group behave like a carousel
14627 * @cfg {Number} bullets show the panel pointer.. default 0
14628 * @cfg {Boolena} autoslide (true|false) auto slide .. default false
14629 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14632 * Create a new TabGroup
14633 * @param {Object} config The config object
14636 Roo.bootstrap.TabGroup = function(config){
14637 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14639 this.navId = Roo.id();
14642 Roo.bootstrap.TabGroup.register(this);
14646 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14649 transition : false,
14655 getAutoCreate : function()
14657 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14659 cfg.cls += ' tab-content';
14661 if (this.carousel) {
14662 cfg.cls += ' carousel slide';
14665 cls : 'carousel-inner'
14668 if(this.bullets > 0){
14671 cls : 'carousel-bullets',
14675 for (var i = 0; i < this.bullets; i++){
14677 cls : 'bullet bullet-' + i
14685 cfg.cn[0].cn = bullets;
14692 initEvents: function()
14694 Roo.log('-------- init events on tab group ---------');
14698 if(this.bullets > 0){
14700 for (var i = 0; i < this.bullets; i++){
14701 var bullet = this.el.select('.bullet-' + i, true).first();
14707 bullet.on('click', (function(e, el, o, ii, t){
14709 e.preventDefault();
14711 _this.showPanel(ii);
14713 }).createDelegate(this, [i, bullet], true));
14718 if(this.autoslide){
14719 this.slideFn = window.setInterval(function() {
14720 _this.showPanelNext();
14725 getChildContainer : function()
14727 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14731 * register a Navigation item
14732 * @param {Roo.bootstrap.NavItem} the navitem to add
14734 register : function(item)
14736 this.tabs.push( item);
14737 item.navId = this.navId; // not really needed..
14741 getActivePanel : function()
14744 Roo.each(this.tabs, function(t) {
14754 getPanelByName : function(n)
14757 Roo.each(this.tabs, function(t) {
14758 if (t.tabId == n) {
14766 indexOfPanel : function(p)
14769 Roo.each(this.tabs, function(t,i) {
14770 if (t.tabId == p.tabId) {
14779 * show a specific panel
14780 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14781 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14783 showPanel : function (pan)
14785 if(this.transition){
14786 Roo.log("waiting for the transitionend");
14790 if (typeof(pan) == 'number') {
14791 pan = this.tabs[pan];
14793 if (typeof(pan) == 'string') {
14794 pan = this.getPanelByName(pan);
14796 if (pan.tabId == this.getActivePanel().tabId) {
14799 var cur = this.getActivePanel();
14801 if (false === cur.fireEvent('beforedeactivate')) {
14805 if(this.bullets > 0){
14806 this.setActiveBullet(this.indexOfPanel(pan));
14809 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14811 this.transition = true;
14812 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14813 var lr = dir == 'next' ? 'left' : 'right';
14814 pan.el.addClass(dir); // or prev
14815 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14816 cur.el.addClass(lr); // or right
14817 pan.el.addClass(lr);
14820 cur.el.on('transitionend', function() {
14821 Roo.log("trans end?");
14823 pan.el.removeClass([lr,dir]);
14824 pan.setActive(true);
14826 cur.el.removeClass([lr]);
14827 cur.setActive(false);
14829 _this.transition = false;
14831 }, this, { single: true } );
14836 cur.setActive(false);
14837 pan.setActive(true);
14842 showPanelNext : function()
14844 var i = this.indexOfPanel(this.getActivePanel());
14846 if (i >= this.tabs.length - 1 && !this.autoslide) {
14850 if (i >= this.tabs.length - 1 && this.autoslide) {
14854 this.showPanel(this.tabs[i+1]);
14857 showPanelPrev : function()
14859 var i = this.indexOfPanel(this.getActivePanel());
14861 if (i < 1 && !this.autoslide) {
14865 if (i < 1 && this.autoslide) {
14866 i = this.tabs.length;
14869 this.showPanel(this.tabs[i-1]);
14872 setActiveBullet : function(i)
14874 Roo.each(this.el.select('.bullet', true).elements, function(el){
14875 el.removeClass('selected');
14878 var bullet = this.el.select('.bullet-' + i, true).first();
14884 bullet.addClass('selected');
14895 Roo.apply(Roo.bootstrap.TabGroup, {
14899 * register a Navigation Group
14900 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14902 register : function(navgrp)
14904 this.groups[navgrp.navId] = navgrp;
14908 * fetch a Navigation Group based on the navigation ID
14909 * if one does not exist , it will get created.
14910 * @param {string} the navgroup to add
14911 * @returns {Roo.bootstrap.NavGroup} the navgroup
14913 get: function(navId) {
14914 if (typeof(this.groups[navId]) == 'undefined') {
14915 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14917 return this.groups[navId] ;
14932 * @class Roo.bootstrap.TabPanel
14933 * @extends Roo.bootstrap.Component
14934 * Bootstrap TabPanel class
14935 * @cfg {Boolean} active panel active
14936 * @cfg {String} html panel content
14937 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14938 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14942 * Create a new TabPanel
14943 * @param {Object} config The config object
14946 Roo.bootstrap.TabPanel = function(config){
14947 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14951 * Fires when the active status changes
14952 * @param {Roo.bootstrap.TabPanel} this
14953 * @param {Boolean} state the new state
14958 * @event beforedeactivate
14959 * Fires before a tab is de-activated - can be used to do validation on a form.
14960 * @param {Roo.bootstrap.TabPanel} this
14961 * @return {Boolean} false if there is an error
14964 'beforedeactivate': true
14967 this.tabId = this.tabId || Roo.id();
14971 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14978 getAutoCreate : function(){
14981 // item is needed for carousel - not sure if it has any effect otherwise
14982 cls: 'tab-pane item',
14983 html: this.html || ''
14987 cfg.cls += ' active';
14991 cfg.tabId = this.tabId;
14998 initEvents: function()
15000 Roo.log('-------- init events on tab panel ---------');
15002 var p = this.parent();
15003 this.navId = this.navId || p.navId;
15005 if (typeof(this.navId) != 'undefined') {
15006 // not really needed.. but just in case.. parent should be a NavGroup.
15007 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15008 Roo.log(['register', tg, this]);
15011 var i = tg.tabs.length - 1;
15013 if(this.active && tg.bullets > 0 && i < tg.bullets){
15014 tg.setActiveBullet(i);
15021 onRender : function(ct, position)
15023 // Roo.log("Call onRender: " + this.xtype);
15025 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15033 setActive: function(state)
15035 Roo.log("panel - set active " + this.tabId + "=" + state);
15037 this.active = state;
15039 this.el.removeClass('active');
15041 } else if (!this.el.hasClass('active')) {
15042 this.el.addClass('active');
15045 this.fireEvent('changed', this, state);
15062 * @class Roo.bootstrap.DateField
15063 * @extends Roo.bootstrap.Input
15064 * Bootstrap DateField class
15065 * @cfg {Number} weekStart default 0
15066 * @cfg {String} viewMode default empty, (months|years)
15067 * @cfg {String} minViewMode default empty, (months|years)
15068 * @cfg {Number} startDate default -Infinity
15069 * @cfg {Number} endDate default Infinity
15070 * @cfg {Boolean} todayHighlight default false
15071 * @cfg {Boolean} todayBtn default false
15072 * @cfg {Boolean} calendarWeeks default false
15073 * @cfg {Object} daysOfWeekDisabled default empty
15074 * @cfg {Boolean} singleMode default false (true | false)
15076 * @cfg {Boolean} keyboardNavigation default true
15077 * @cfg {String} language default en
15080 * Create a new DateField
15081 * @param {Object} config The config object
15084 Roo.bootstrap.DateField = function(config){
15085 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15089 * Fires when this field show.
15090 * @param {Roo.bootstrap.DateField} this
15091 * @param {Mixed} date The date value
15096 * Fires when this field hide.
15097 * @param {Roo.bootstrap.DateField} this
15098 * @param {Mixed} date The date value
15103 * Fires when select a date.
15104 * @param {Roo.bootstrap.DateField} this
15105 * @param {Mixed} date The date value
15111 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15114 * @cfg {String} format
15115 * The default date format string which can be overriden for localization support. The format must be
15116 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15120 * @cfg {String} altFormats
15121 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15122 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15124 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15132 todayHighlight : false,
15138 keyboardNavigation: true,
15140 calendarWeeks: false,
15142 startDate: -Infinity,
15146 daysOfWeekDisabled: [],
15150 singleMode : false,
15152 UTCDate: function()
15154 return new Date(Date.UTC.apply(Date, arguments));
15157 UTCToday: function()
15159 var today = new Date();
15160 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15163 getDate: function() {
15164 var d = this.getUTCDate();
15165 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15168 getUTCDate: function() {
15172 setDate: function(d) {
15173 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15176 setUTCDate: function(d) {
15178 this.setValue(this.formatDate(this.date));
15181 onRender: function(ct, position)
15184 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15186 this.language = this.language || 'en';
15187 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15188 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15190 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15191 this.format = this.format || 'm/d/y';
15192 this.isInline = false;
15193 this.isInput = true;
15194 this.component = this.el.select('.add-on', true).first() || false;
15195 this.component = (this.component && this.component.length === 0) ? false : this.component;
15196 this.hasInput = this.component && this.inputEL().length;
15198 if (typeof(this.minViewMode === 'string')) {
15199 switch (this.minViewMode) {
15201 this.minViewMode = 1;
15204 this.minViewMode = 2;
15207 this.minViewMode = 0;
15212 if (typeof(this.viewMode === 'string')) {
15213 switch (this.viewMode) {
15226 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15228 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15230 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15232 this.picker().on('mousedown', this.onMousedown, this);
15233 this.picker().on('click', this.onClick, this);
15235 this.picker().addClass('datepicker-dropdown');
15237 this.startViewMode = this.viewMode;
15239 if(this.singleMode){
15240 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15241 v.setVisibilityMode(Roo.Element.DISPLAY)
15245 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15246 v.setStyle('width', '189px');
15250 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15251 if(!this.calendarWeeks){
15256 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15257 v.attr('colspan', function(i, val){
15258 return parseInt(val) + 1;
15263 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15265 this.setStartDate(this.startDate);
15266 this.setEndDate(this.endDate);
15268 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15275 if(this.isInline) {
15280 picker : function()
15282 return this.pickerEl;
15283 // return this.el.select('.datepicker', true).first();
15286 fillDow: function()
15288 var dowCnt = this.weekStart;
15297 if(this.calendarWeeks){
15305 while (dowCnt < this.weekStart + 7) {
15309 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15313 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15316 fillMonths: function()
15319 var months = this.picker().select('>.datepicker-months td', true).first();
15321 months.dom.innerHTML = '';
15327 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15330 months.createChild(month);
15337 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;
15339 if (this.date < this.startDate) {
15340 this.viewDate = new Date(this.startDate);
15341 } else if (this.date > this.endDate) {
15342 this.viewDate = new Date(this.endDate);
15344 this.viewDate = new Date(this.date);
15352 var d = new Date(this.viewDate),
15353 year = d.getUTCFullYear(),
15354 month = d.getUTCMonth(),
15355 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15356 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15357 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15358 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15359 currentDate = this.date && this.date.valueOf(),
15360 today = this.UTCToday();
15362 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15364 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15366 // this.picker.select('>tfoot th.today').
15367 // .text(dates[this.language].today)
15368 // .toggle(this.todayBtn !== false);
15370 this.updateNavArrows();
15373 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15375 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15377 prevMonth.setUTCDate(day);
15379 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15381 var nextMonth = new Date(prevMonth);
15383 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15385 nextMonth = nextMonth.valueOf();
15387 var fillMonths = false;
15389 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15391 while(prevMonth.valueOf() < nextMonth) {
15394 if (prevMonth.getUTCDay() === this.weekStart) {
15396 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15404 if(this.calendarWeeks){
15405 // ISO 8601: First week contains first thursday.
15406 // ISO also states week starts on Monday, but we can be more abstract here.
15408 // Start of current week: based on weekstart/current date
15409 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15410 // Thursday of this week
15411 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15412 // First Thursday of year, year from thursday
15413 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15414 // Calendar week: ms between thursdays, div ms per day, div 7 days
15415 calWeek = (th - yth) / 864e5 / 7 + 1;
15417 fillMonths.cn.push({
15425 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15427 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15430 if (this.todayHighlight &&
15431 prevMonth.getUTCFullYear() == today.getFullYear() &&
15432 prevMonth.getUTCMonth() == today.getMonth() &&
15433 prevMonth.getUTCDate() == today.getDate()) {
15434 clsName += ' today';
15437 if (currentDate && prevMonth.valueOf() === currentDate) {
15438 clsName += ' active';
15441 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15442 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15443 clsName += ' disabled';
15446 fillMonths.cn.push({
15448 cls: 'day ' + clsName,
15449 html: prevMonth.getDate()
15452 prevMonth.setDate(prevMonth.getDate()+1);
15455 var currentYear = this.date && this.date.getUTCFullYear();
15456 var currentMonth = this.date && this.date.getUTCMonth();
15458 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15460 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15461 v.removeClass('active');
15463 if(currentYear === year && k === currentMonth){
15464 v.addClass('active');
15467 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15468 v.addClass('disabled');
15474 year = parseInt(year/10, 10) * 10;
15476 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15478 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15481 for (var i = -1; i < 11; i++) {
15482 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15484 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15492 showMode: function(dir)
15495 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15498 Roo.each(this.picker().select('>div',true).elements, function(v){
15499 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15502 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15507 if(this.isInline) return;
15509 this.picker().removeClass(['bottom', 'top']);
15511 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15513 * place to the top of element!
15517 this.picker().addClass('top');
15518 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15523 this.picker().addClass('bottom');
15525 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15528 parseDate : function(value)
15530 if(!value || value instanceof Date){
15533 var v = Date.parseDate(value, this.format);
15534 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15535 v = Date.parseDate(value, 'Y-m-d');
15537 if(!v && this.altFormats){
15538 if(!this.altFormatsArray){
15539 this.altFormatsArray = this.altFormats.split("|");
15541 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15542 v = Date.parseDate(value, this.altFormatsArray[i]);
15548 formatDate : function(date, fmt)
15550 return (!date || !(date instanceof Date)) ?
15551 date : date.dateFormat(fmt || this.format);
15554 onFocus : function()
15556 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15560 onBlur : function()
15562 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15564 var d = this.inputEl().getValue();
15573 this.picker().show();
15577 this.fireEvent('show', this, this.date);
15582 if(this.isInline) return;
15583 this.picker().hide();
15584 this.viewMode = this.startViewMode;
15587 this.fireEvent('hide', this, this.date);
15591 onMousedown: function(e)
15593 e.stopPropagation();
15594 e.preventDefault();
15599 Roo.bootstrap.DateField.superclass.keyup.call(this);
15603 setValue: function(v)
15606 // v can be a string or a date..
15609 var d = new Date(this.parseDate(v) ).clearTime();
15611 if(isNaN(d.getTime())){
15612 this.date = this.viewDate = '';
15613 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15617 v = this.formatDate(d);
15619 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15621 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15625 this.fireEvent('select', this, this.date);
15629 getValue: function()
15631 return this.formatDate(this.date);
15634 fireKey: function(e)
15636 if (!this.picker().isVisible()){
15637 if (e.keyCode == 27) // allow escape to hide and re-show picker
15642 var dateChanged = false,
15644 newDate, newViewDate;
15649 e.preventDefault();
15653 if (!this.keyboardNavigation) break;
15654 dir = e.keyCode == 37 ? -1 : 1;
15657 newDate = this.moveYear(this.date, dir);
15658 newViewDate = this.moveYear(this.viewDate, dir);
15659 } else if (e.shiftKey){
15660 newDate = this.moveMonth(this.date, dir);
15661 newViewDate = this.moveMonth(this.viewDate, dir);
15663 newDate = new Date(this.date);
15664 newDate.setUTCDate(this.date.getUTCDate() + dir);
15665 newViewDate = new Date(this.viewDate);
15666 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15668 if (this.dateWithinRange(newDate)){
15669 this.date = newDate;
15670 this.viewDate = newViewDate;
15671 this.setValue(this.formatDate(this.date));
15673 e.preventDefault();
15674 dateChanged = true;
15679 if (!this.keyboardNavigation) break;
15680 dir = e.keyCode == 38 ? -1 : 1;
15682 newDate = this.moveYear(this.date, dir);
15683 newViewDate = this.moveYear(this.viewDate, dir);
15684 } else if (e.shiftKey){
15685 newDate = this.moveMonth(this.date, dir);
15686 newViewDate = this.moveMonth(this.viewDate, dir);
15688 newDate = new Date(this.date);
15689 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15690 newViewDate = new Date(this.viewDate);
15691 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15693 if (this.dateWithinRange(newDate)){
15694 this.date = newDate;
15695 this.viewDate = newViewDate;
15696 this.setValue(this.formatDate(this.date));
15698 e.preventDefault();
15699 dateChanged = true;
15703 this.setValue(this.formatDate(this.date));
15705 e.preventDefault();
15708 this.setValue(this.formatDate(this.date));
15722 onClick: function(e)
15724 e.stopPropagation();
15725 e.preventDefault();
15727 var target = e.getTarget();
15729 if(target.nodeName.toLowerCase() === 'i'){
15730 target = Roo.get(target).dom.parentNode;
15733 var nodeName = target.nodeName;
15734 var className = target.className;
15735 var html = target.innerHTML;
15736 //Roo.log(nodeName);
15738 switch(nodeName.toLowerCase()) {
15740 switch(className) {
15746 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15747 switch(this.viewMode){
15749 this.viewDate = this.moveMonth(this.viewDate, dir);
15753 this.viewDate = this.moveYear(this.viewDate, dir);
15759 var date = new Date();
15760 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15762 this.setValue(this.formatDate(this.date));
15769 if (className.indexOf('disabled') < 0) {
15770 this.viewDate.setUTCDate(1);
15771 if (className.indexOf('month') > -1) {
15772 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15774 var year = parseInt(html, 10) || 0;
15775 this.viewDate.setUTCFullYear(year);
15779 if(this.singleMode){
15780 this.setValue(this.formatDate(this.viewDate));
15791 //Roo.log(className);
15792 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15793 var day = parseInt(html, 10) || 1;
15794 var year = this.viewDate.getUTCFullYear(),
15795 month = this.viewDate.getUTCMonth();
15797 if (className.indexOf('old') > -1) {
15804 } else if (className.indexOf('new') > -1) {
15812 //Roo.log([year,month,day]);
15813 this.date = this.UTCDate(year, month, day,0,0,0,0);
15814 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15816 //Roo.log(this.formatDate(this.date));
15817 this.setValue(this.formatDate(this.date));
15824 setStartDate: function(startDate)
15826 this.startDate = startDate || -Infinity;
15827 if (this.startDate !== -Infinity) {
15828 this.startDate = this.parseDate(this.startDate);
15831 this.updateNavArrows();
15834 setEndDate: function(endDate)
15836 this.endDate = endDate || Infinity;
15837 if (this.endDate !== Infinity) {
15838 this.endDate = this.parseDate(this.endDate);
15841 this.updateNavArrows();
15844 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15846 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15847 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15848 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15850 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15851 return parseInt(d, 10);
15854 this.updateNavArrows();
15857 updateNavArrows: function()
15859 if(this.singleMode){
15863 var d = new Date(this.viewDate),
15864 year = d.getUTCFullYear(),
15865 month = d.getUTCMonth();
15867 Roo.each(this.picker().select('.prev', true).elements, function(v){
15869 switch (this.viewMode) {
15872 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15878 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15885 Roo.each(this.picker().select('.next', true).elements, function(v){
15887 switch (this.viewMode) {
15890 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15896 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15904 moveMonth: function(date, dir)
15906 if (!dir) return date;
15907 var new_date = new Date(date.valueOf()),
15908 day = new_date.getUTCDate(),
15909 month = new_date.getUTCMonth(),
15910 mag = Math.abs(dir),
15912 dir = dir > 0 ? 1 : -1;
15915 // If going back one month, make sure month is not current month
15916 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15918 return new_date.getUTCMonth() == month;
15920 // If going forward one month, make sure month is as expected
15921 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15923 return new_date.getUTCMonth() != new_month;
15925 new_month = month + dir;
15926 new_date.setUTCMonth(new_month);
15927 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15928 if (new_month < 0 || new_month > 11)
15929 new_month = (new_month + 12) % 12;
15931 // For magnitudes >1, move one month at a time...
15932 for (var i=0; i<mag; i++)
15933 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15934 new_date = this.moveMonth(new_date, dir);
15935 // ...then reset the day, keeping it in the new month
15936 new_month = new_date.getUTCMonth();
15937 new_date.setUTCDate(day);
15939 return new_month != new_date.getUTCMonth();
15942 // Common date-resetting loop -- if date is beyond end of month, make it
15945 new_date.setUTCDate(--day);
15946 new_date.setUTCMonth(new_month);
15951 moveYear: function(date, dir)
15953 return this.moveMonth(date, dir*12);
15956 dateWithinRange: function(date)
15958 return date >= this.startDate && date <= this.endDate;
15964 this.picker().remove();
15969 Roo.apply(Roo.bootstrap.DateField, {
15980 html: '<i class="fa fa-arrow-left"/>'
15990 html: '<i class="fa fa-arrow-right"/>'
16032 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16033 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16034 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16035 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16036 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16049 navFnc: 'FullYear',
16054 navFnc: 'FullYear',
16059 Roo.apply(Roo.bootstrap.DateField, {
16063 cls: 'datepicker dropdown-menu roo-dynamic',
16067 cls: 'datepicker-days',
16071 cls: 'table-condensed',
16073 Roo.bootstrap.DateField.head,
16077 Roo.bootstrap.DateField.footer
16084 cls: 'datepicker-months',
16088 cls: 'table-condensed',
16090 Roo.bootstrap.DateField.head,
16091 Roo.bootstrap.DateField.content,
16092 Roo.bootstrap.DateField.footer
16099 cls: 'datepicker-years',
16103 cls: 'table-condensed',
16105 Roo.bootstrap.DateField.head,
16106 Roo.bootstrap.DateField.content,
16107 Roo.bootstrap.DateField.footer
16126 * @class Roo.bootstrap.TimeField
16127 * @extends Roo.bootstrap.Input
16128 * Bootstrap DateField class
16132 * Create a new TimeField
16133 * @param {Object} config The config object
16136 Roo.bootstrap.TimeField = function(config){
16137 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16141 * Fires when this field show.
16142 * @param {Roo.bootstrap.DateField} thisthis
16143 * @param {Mixed} date The date value
16148 * Fires when this field hide.
16149 * @param {Roo.bootstrap.DateField} this
16150 * @param {Mixed} date The date value
16155 * Fires when select a date.
16156 * @param {Roo.bootstrap.DateField} this
16157 * @param {Mixed} date The date value
16163 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16166 * @cfg {String} format
16167 * The default time format string which can be overriden for localization support. The format must be
16168 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16172 onRender: function(ct, position)
16175 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16177 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16179 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16181 this.pop = this.picker().select('>.datepicker-time',true).first();
16182 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16184 this.picker().on('mousedown', this.onMousedown, this);
16185 this.picker().on('click', this.onClick, this);
16187 this.picker().addClass('datepicker-dropdown');
16192 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16193 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16194 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16195 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16196 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16197 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16201 fireKey: function(e){
16202 if (!this.picker().isVisible()){
16203 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16209 e.preventDefault();
16217 this.onTogglePeriod();
16220 this.onIncrementMinutes();
16223 this.onDecrementMinutes();
16232 onClick: function(e) {
16233 e.stopPropagation();
16234 e.preventDefault();
16237 picker : function()
16239 return this.el.select('.datepicker', true).first();
16242 fillTime: function()
16244 var time = this.pop.select('tbody', true).first();
16246 time.dom.innerHTML = '';
16261 cls: 'hours-up glyphicon glyphicon-chevron-up'
16281 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16302 cls: 'timepicker-hour',
16317 cls: 'timepicker-minute',
16332 cls: 'btn btn-primary period',
16354 cls: 'hours-down glyphicon glyphicon-chevron-down'
16374 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16392 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16399 var hours = this.time.getHours();
16400 var minutes = this.time.getMinutes();
16413 hours = hours - 12;
16417 hours = '0' + hours;
16421 minutes = '0' + minutes;
16424 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16425 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16426 this.pop.select('button', true).first().dom.innerHTML = period;
16432 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16434 var cls = ['bottom'];
16436 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16443 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16448 this.picker().addClass(cls.join('-'));
16452 Roo.each(cls, function(c){
16454 _this.picker().setTop(_this.inputEl().getHeight());
16458 _this.picker().setTop(0 - _this.picker().getHeight());
16463 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16467 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16474 onFocus : function()
16476 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16480 onBlur : function()
16482 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16488 this.picker().show();
16493 this.fireEvent('show', this, this.date);
16498 this.picker().hide();
16501 this.fireEvent('hide', this, this.date);
16504 setTime : function()
16507 this.setValue(this.time.format(this.format));
16509 this.fireEvent('select', this, this.date);
16514 onMousedown: function(e){
16515 e.stopPropagation();
16516 e.preventDefault();
16519 onIncrementHours: function()
16521 Roo.log('onIncrementHours');
16522 this.time = this.time.add(Date.HOUR, 1);
16527 onDecrementHours: function()
16529 Roo.log('onDecrementHours');
16530 this.time = this.time.add(Date.HOUR, -1);
16534 onIncrementMinutes: function()
16536 Roo.log('onIncrementMinutes');
16537 this.time = this.time.add(Date.MINUTE, 1);
16541 onDecrementMinutes: function()
16543 Roo.log('onDecrementMinutes');
16544 this.time = this.time.add(Date.MINUTE, -1);
16548 onTogglePeriod: function()
16550 Roo.log('onTogglePeriod');
16551 this.time = this.time.add(Date.HOUR, 12);
16558 Roo.apply(Roo.bootstrap.TimeField, {
16588 cls: 'btn btn-info ok',
16600 Roo.apply(Roo.bootstrap.TimeField, {
16604 cls: 'datepicker dropdown-menu',
16608 cls: 'datepicker-time',
16612 cls: 'table-condensed',
16614 Roo.bootstrap.TimeField.content,
16615 Roo.bootstrap.TimeField.footer
16634 * @class Roo.bootstrap.MonthField
16635 * @extends Roo.bootstrap.Input
16636 * Bootstrap MonthField class
16638 * @cfg {String} language default en
16641 * Create a new MonthField
16642 * @param {Object} config The config object
16645 Roo.bootstrap.MonthField = function(config){
16646 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16651 * Fires when this field show.
16652 * @param {Roo.bootstrap.MonthField} this
16653 * @param {Mixed} date The date value
16658 * Fires when this field hide.
16659 * @param {Roo.bootstrap.MonthField} this
16660 * @param {Mixed} date The date value
16665 * Fires when select a date.
16666 * @param {Roo.bootstrap.MonthField} this
16667 * @param {String} oldvalue The old value
16668 * @param {String} newvalue The new value
16674 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16676 onRender: function(ct, position)
16679 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16681 this.language = this.language || 'en';
16682 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16683 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16685 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16686 this.isInline = false;
16687 this.isInput = true;
16688 this.component = this.el.select('.add-on', true).first() || false;
16689 this.component = (this.component && this.component.length === 0) ? false : this.component;
16690 this.hasInput = this.component && this.inputEL().length;
16692 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16694 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16696 this.picker().on('mousedown', this.onMousedown, this);
16697 this.picker().on('click', this.onClick, this);
16699 this.picker().addClass('datepicker-dropdown');
16701 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16702 v.setStyle('width', '189px');
16709 if(this.isInline) {
16715 setValue: function(v, suppressEvent)
16717 var o = this.getValue();
16719 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16723 if(suppressEvent !== true){
16724 this.fireEvent('select', this, o, v);
16729 getValue: function()
16734 onClick: function(e)
16736 e.stopPropagation();
16737 e.preventDefault();
16739 var target = e.getTarget();
16741 if(target.nodeName.toLowerCase() === 'i'){
16742 target = Roo.get(target).dom.parentNode;
16745 var nodeName = target.nodeName;
16746 var className = target.className;
16747 var html = target.innerHTML;
16749 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16753 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16755 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16761 picker : function()
16763 return this.pickerEl;
16766 fillMonths: function()
16769 var months = this.picker().select('>.datepicker-months td', true).first();
16771 months.dom.innerHTML = '';
16777 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16780 months.createChild(month);
16789 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16790 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16793 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16794 e.removeClass('active');
16796 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16797 e.addClass('active');
16804 if(this.isInline) return;
16806 this.picker().removeClass(['bottom', 'top']);
16808 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16810 * place to the top of element!
16814 this.picker().addClass('top');
16815 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16820 this.picker().addClass('bottom');
16822 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16825 onFocus : function()
16827 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16831 onBlur : function()
16833 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16835 var d = this.inputEl().getValue();
16844 this.picker().show();
16845 this.picker().select('>.datepicker-months', true).first().show();
16849 this.fireEvent('show', this, this.date);
16854 if(this.isInline) return;
16855 this.picker().hide();
16856 this.fireEvent('hide', this, this.date);
16860 onMousedown: function(e)
16862 e.stopPropagation();
16863 e.preventDefault();
16868 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16872 fireKey: function(e)
16874 if (!this.picker().isVisible()){
16875 if (e.keyCode == 27) // allow escape to hide and re-show picker
16885 e.preventDefault();
16889 dir = e.keyCode == 37 ? -1 : 1;
16891 this.vIndex = this.vIndex + dir;
16893 if(this.vIndex < 0){
16897 if(this.vIndex > 11){
16901 if(isNaN(this.vIndex)){
16905 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16911 dir = e.keyCode == 38 ? -1 : 1;
16913 this.vIndex = this.vIndex + dir * 4;
16915 if(this.vIndex < 0){
16919 if(this.vIndex > 11){
16923 if(isNaN(this.vIndex)){
16927 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16932 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16933 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16937 e.preventDefault();
16940 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16941 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16957 this.picker().remove();
16962 Roo.apply(Roo.bootstrap.MonthField, {
16981 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16982 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16987 Roo.apply(Roo.bootstrap.MonthField, {
16991 cls: 'datepicker dropdown-menu roo-dynamic',
16995 cls: 'datepicker-months',
16999 cls: 'table-condensed',
17001 Roo.bootstrap.DateField.content
17021 * @class Roo.bootstrap.CheckBox
17022 * @extends Roo.bootstrap.Input
17023 * Bootstrap CheckBox class
17025 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17026 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17027 * @cfg {String} boxLabel The text that appears beside the checkbox
17028 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17029 * @cfg {Boolean} checked initnal the element
17030 * @cfg {Boolean} inline inline the element (default false)
17031 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17034 * Create a new CheckBox
17035 * @param {Object} config The config object
17038 Roo.bootstrap.CheckBox = function(config){
17039 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17044 * Fires when the element is checked or unchecked.
17045 * @param {Roo.bootstrap.CheckBox} this This input
17046 * @param {Boolean} checked The new checked value
17053 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17055 inputType: 'checkbox',
17063 getAutoCreate : function()
17065 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17071 cfg.cls = 'form-group ' + this.inputType; //input-group
17074 cfg.cls += ' ' + this.inputType + '-inline';
17080 type : this.inputType,
17081 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17082 cls : 'roo-' + this.inputType, //'form-box',
17083 placeholder : this.placeholder || ''
17087 if (this.weight) { // Validity check?
17088 cfg.cls += " " + this.inputType + "-" + this.weight;
17091 if (this.disabled) {
17092 input.disabled=true;
17096 input.checked = this.checked;
17100 input.name = this.name;
17104 input.cls += ' input-' + this.size;
17109 ['xs','sm','md','lg'].map(function(size){
17110 if (settings[size]) {
17111 cfg.cls += ' col-' + size + '-' + settings[size];
17115 var inputblock = input;
17117 if (this.before || this.after) {
17120 cls : 'input-group',
17125 inputblock.cn.push({
17127 cls : 'input-group-addon',
17132 inputblock.cn.push(input);
17135 inputblock.cn.push({
17137 cls : 'input-group-addon',
17144 if (align ==='left' && this.fieldLabel.length) {
17145 Roo.log("left and has label");
17151 cls : 'control-label col-md-' + this.labelWidth,
17152 html : this.fieldLabel
17156 cls : "col-md-" + (12 - this.labelWidth),
17163 } else if ( this.fieldLabel.length) {
17168 tag: this.boxLabel ? 'span' : 'label',
17170 cls: 'control-label box-input-label',
17171 //cls : 'input-group-addon',
17172 html : this.fieldLabel
17182 Roo.log(" no label && no align");
17183 cfg.cn = [ inputblock ] ;
17188 var boxLabelCfg = {
17190 //'for': id, // box label is handled by onclick - so no for...
17192 html: this.boxLabel
17196 boxLabelCfg.tooltip = this.tooltip;
17199 cfg.cn.push(boxLabelCfg);
17209 * return the real input element.
17211 inputEl: function ()
17213 return this.el.select('input.roo-' + this.inputType,true).first();
17216 labelEl: function()
17218 return this.el.select('label.control-label',true).first();
17220 /* depricated... */
17224 return this.labelEl();
17227 initEvents : function()
17229 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17231 this.inputEl().on('click', this.onClick, this);
17233 if (this.boxLabel) {
17234 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17237 this.startValue = this.getValue();
17240 Roo.bootstrap.CheckBox.register(this);
17244 onClick : function()
17246 this.setChecked(!this.checked);
17249 setChecked : function(state,suppressEvent)
17251 this.startValue = this.getValue();
17253 if(this.inputType == 'radio'){
17255 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17256 e.dom.checked = false;
17259 this.inputEl().dom.checked = true;
17261 this.inputEl().dom.value = this.inputValue;
17263 if(suppressEvent !== true){
17264 this.fireEvent('check', this, true);
17272 this.checked = state;
17274 this.inputEl().dom.checked = state;
17276 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17278 if(suppressEvent !== true){
17279 this.fireEvent('check', this, state);
17285 getValue : function()
17287 if(this.inputType == 'radio'){
17288 return this.getGroupValue();
17291 return this.inputEl().getValue();
17295 getGroupValue : function()
17297 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17301 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17304 setValue : function(v,suppressEvent)
17306 if(this.inputType == 'radio'){
17307 this.setGroupValue(v, suppressEvent);
17311 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17316 setGroupValue : function(v, suppressEvent)
17318 this.startValue = this.getValue();
17320 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17321 e.dom.checked = false;
17323 if(e.dom.value == v){
17324 e.dom.checked = true;
17328 if(suppressEvent !== true){
17329 this.fireEvent('check', this, true);
17337 validate : function()
17341 (this.inputType == 'radio' && this.validateRadio()) ||
17342 (this.inputType == 'checkbox' && this.validateCheckbox())
17348 this.markInvalid();
17352 validateRadio : function()
17356 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17357 if(!e.dom.checked){
17369 validateCheckbox : function()
17372 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17375 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17383 for(var i in group){
17388 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17395 * Mark this field as valid
17397 markValid : function()
17399 if(this.allowBlank){
17405 this.fireEvent('valid', this);
17407 if(this.inputType == 'radio'){
17408 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17409 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17410 e.findParent('.form-group', false, true).addClass(_this.validClass);
17417 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17418 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17422 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17428 for(var i in group){
17429 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17430 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17435 * Mark this field as invalid
17436 * @param {String} msg The validation message
17438 markInvalid : function(msg)
17440 if(this.allowBlank){
17446 this.fireEvent('invalid', this, msg);
17448 if(this.inputType == 'radio'){
17449 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17450 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17451 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17458 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17459 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17463 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17469 for(var i in group){
17470 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17471 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17478 Roo.apply(Roo.bootstrap.CheckBox, {
17483 * register a CheckBox Group
17484 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17486 register : function(checkbox)
17488 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17489 this.groups[checkbox.groupId] = {};
17492 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17496 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17500 * fetch a CheckBox Group based on the group ID
17501 * @param {string} the group ID
17502 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17504 get: function(groupId) {
17505 if (typeof(this.groups[groupId]) == 'undefined') {
17509 return this.groups[groupId] ;
17521 *<div class="radio">
17523 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17524 Option one is this and that—be sure to include why it's great
17531 *<label class="radio-inline">fieldLabel</label>
17532 *<label class="radio-inline">
17533 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17541 * @class Roo.bootstrap.Radio
17542 * @extends Roo.bootstrap.CheckBox
17543 * Bootstrap Radio class
17546 * Create a new Radio
17547 * @param {Object} config The config object
17550 Roo.bootstrap.Radio = function(config){
17551 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17555 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17557 inputType: 'radio',
17561 getAutoCreate : function()
17563 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17564 align = align || 'left'; // default...
17571 tag : this.inline ? 'span' : 'div',
17576 var inline = this.inline ? ' radio-inline' : '';
17580 // does not need for, as we wrap the input with it..
17582 cls : 'control-label box-label' + inline,
17585 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17589 //cls : 'control-label' + inline,
17590 html : this.fieldLabel,
17591 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17600 type : this.inputType,
17601 //value : (!this.checked) ? this.valueOff : this.inputValue,
17602 value : this.inputValue,
17604 placeholder : this.placeholder || '' // ?? needed????
17607 if (this.weight) { // Validity check?
17608 input.cls += " radio-" + this.weight;
17610 if (this.disabled) {
17611 input.disabled=true;
17615 input.checked = this.checked;
17619 input.name = this.name;
17623 input.cls += ' input-' + this.size;
17626 //?? can span's inline have a width??
17629 ['xs','sm','md','lg'].map(function(size){
17630 if (settings[size]) {
17631 cfg.cls += ' col-' + size + '-' + settings[size];
17635 var inputblock = input;
17637 if (this.before || this.after) {
17640 cls : 'input-group',
17645 inputblock.cn.push({
17647 cls : 'input-group-addon',
17651 inputblock.cn.push(input);
17653 inputblock.cn.push({
17655 cls : 'input-group-addon',
17663 if (this.fieldLabel && this.fieldLabel.length) {
17664 cfg.cn.push(fieldLabel);
17667 // normal bootstrap puts the input inside the label.
17668 // however with our styled version - it has to go after the input.
17670 //lbl.cn.push(inputblock);
17674 cls: 'radio' + inline,
17681 cfg.cn.push( lblwrap);
17686 html: this.boxLabel
17695 initEvents : function()
17697 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17699 this.inputEl().on('click', this.onClick, this);
17700 if (this.boxLabel) {
17701 Roo.log('find label')
17702 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17707 inputEl: function ()
17709 return this.el.select('input.roo-radio',true).first();
17711 onClick : function()
17714 this.setChecked(true);
17717 setChecked : function(state,suppressEvent)
17720 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17721 v.dom.checked = false;
17724 Roo.log(this.inputEl().dom);
17725 this.checked = state;
17726 this.inputEl().dom.checked = state;
17728 if(suppressEvent !== true){
17729 this.fireEvent('check', this, state);
17732 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17736 getGroupValue : function()
17739 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17740 if(v.dom.checked == true){
17741 value = v.dom.value;
17749 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17750 * @return {Mixed} value The field value
17752 getValue : function(){
17753 return this.getGroupValue();
17759 //<script type="text/javascript">
17762 * Based Ext JS Library 1.1.1
17763 * Copyright(c) 2006-2007, Ext JS, LLC.
17769 * @class Roo.HtmlEditorCore
17770 * @extends Roo.Component
17771 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17773 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17776 Roo.HtmlEditorCore = function(config){
17779 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17784 * @event initialize
17785 * Fires when the editor is fully initialized (including the iframe)
17786 * @param {Roo.HtmlEditorCore} this
17791 * Fires when the editor is first receives the focus. Any insertion must wait
17792 * until after this event.
17793 * @param {Roo.HtmlEditorCore} this
17797 * @event beforesync
17798 * Fires before the textarea is updated with content from the editor iframe. Return false
17799 * to cancel the sync.
17800 * @param {Roo.HtmlEditorCore} this
17801 * @param {String} html
17805 * @event beforepush
17806 * Fires before the iframe editor is updated with content from the textarea. Return false
17807 * to cancel the push.
17808 * @param {Roo.HtmlEditorCore} this
17809 * @param {String} html
17814 * Fires when the textarea is updated with content from the editor iframe.
17815 * @param {Roo.HtmlEditorCore} this
17816 * @param {String} html
17821 * Fires when the iframe editor is updated with content from the textarea.
17822 * @param {Roo.HtmlEditorCore} this
17823 * @param {String} html
17828 * @event editorevent
17829 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17830 * @param {Roo.HtmlEditorCore} this
17836 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17838 // defaults : white / black...
17839 this.applyBlacklists();
17846 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17850 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17856 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17861 * @cfg {Number} height (in pixels)
17865 * @cfg {Number} width (in pixels)
17870 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17873 stylesheets: false,
17878 // private properties
17879 validationEvent : false,
17881 initialized : false,
17883 sourceEditMode : false,
17884 onFocus : Roo.emptyFn,
17886 hideMode:'offsets',
17890 // blacklist + whitelisted elements..
17897 * Protected method that will not generally be called directly. It
17898 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17899 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17901 getDocMarkup : function(){
17905 // inherit styels from page...??
17906 if (this.stylesheets === false) {
17908 Roo.get(document.head).select('style').each(function(node) {
17909 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17912 Roo.get(document.head).select('link').each(function(node) {
17913 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17916 } else if (!this.stylesheets.length) {
17918 st = '<style type="text/css">' +
17919 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17925 st += '<style type="text/css">' +
17926 'IMG { cursor: pointer } ' +
17930 return '<html><head>' + st +
17931 //<style type="text/css">' +
17932 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17934 ' </head><body class="roo-htmleditor-body"></body></html>';
17938 onRender : function(ct, position)
17941 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17942 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17945 this.el.dom.style.border = '0 none';
17946 this.el.dom.setAttribute('tabIndex', -1);
17947 this.el.addClass('x-hidden hide');
17951 if(Roo.isIE){ // fix IE 1px bogus margin
17952 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17956 this.frameId = Roo.id();
17960 var iframe = this.owner.wrap.createChild({
17962 cls: 'form-control', // bootstrap..
17964 name: this.frameId,
17965 frameBorder : 'no',
17966 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17971 this.iframe = iframe.dom;
17973 this.assignDocWin();
17975 this.doc.designMode = 'on';
17978 this.doc.write(this.getDocMarkup());
17982 var task = { // must defer to wait for browser to be ready
17984 //console.log("run task?" + this.doc.readyState);
17985 this.assignDocWin();
17986 if(this.doc.body || this.doc.readyState == 'complete'){
17988 this.doc.designMode="on";
17992 Roo.TaskMgr.stop(task);
17993 this.initEditor.defer(10, this);
18000 Roo.TaskMgr.start(task);
18005 onResize : function(w, h)
18007 Roo.log('resize: ' +w + ',' + h );
18008 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18012 if(typeof w == 'number'){
18014 this.iframe.style.width = w + 'px';
18016 if(typeof h == 'number'){
18018 this.iframe.style.height = h + 'px';
18020 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18027 * Toggles the editor between standard and source edit mode.
18028 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18030 toggleSourceEdit : function(sourceEditMode){
18032 this.sourceEditMode = sourceEditMode === true;
18034 if(this.sourceEditMode){
18036 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18039 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18040 //this.iframe.className = '';
18043 //this.setSize(this.owner.wrap.getSize());
18044 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18051 * Protected method that will not generally be called directly. If you need/want
18052 * custom HTML cleanup, this is the method you should override.
18053 * @param {String} html The HTML to be cleaned
18054 * return {String} The cleaned HTML
18056 cleanHtml : function(html){
18057 html = String(html);
18058 if(html.length > 5){
18059 if(Roo.isSafari){ // strip safari nonsense
18060 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18063 if(html == ' '){
18070 * HTML Editor -> Textarea
18071 * Protected method that will not generally be called directly. Syncs the contents
18072 * of the editor iframe with the textarea.
18074 syncValue : function(){
18075 if(this.initialized){
18076 var bd = (this.doc.body || this.doc.documentElement);
18077 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18078 var html = bd.innerHTML;
18080 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18081 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18083 html = '<div style="'+m[0]+'">' + html + '</div>';
18086 html = this.cleanHtml(html);
18087 // fix up the special chars.. normaly like back quotes in word...
18088 // however we do not want to do this with chinese..
18089 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18090 var cc = b.charCodeAt();
18092 (cc >= 0x4E00 && cc < 0xA000 ) ||
18093 (cc >= 0x3400 && cc < 0x4E00 ) ||
18094 (cc >= 0xf900 && cc < 0xfb00 )
18100 if(this.owner.fireEvent('beforesync', this, html) !== false){
18101 this.el.dom.value = html;
18102 this.owner.fireEvent('sync', this, html);
18108 * Protected method that will not generally be called directly. Pushes the value of the textarea
18109 * into the iframe editor.
18111 pushValue : function(){
18112 if(this.initialized){
18113 var v = this.el.dom.value.trim();
18115 // if(v.length < 1){
18119 if(this.owner.fireEvent('beforepush', this, v) !== false){
18120 var d = (this.doc.body || this.doc.documentElement);
18122 this.cleanUpPaste();
18123 this.el.dom.value = d.innerHTML;
18124 this.owner.fireEvent('push', this, v);
18130 deferFocus : function(){
18131 this.focus.defer(10, this);
18135 focus : function(){
18136 if(this.win && !this.sourceEditMode){
18143 assignDocWin: function()
18145 var iframe = this.iframe;
18148 this.doc = iframe.contentWindow.document;
18149 this.win = iframe.contentWindow;
18151 // if (!Roo.get(this.frameId)) {
18154 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18155 // this.win = Roo.get(this.frameId).dom.contentWindow;
18157 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18161 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18162 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18167 initEditor : function(){
18168 //console.log("INIT EDITOR");
18169 this.assignDocWin();
18173 this.doc.designMode="on";
18175 this.doc.write(this.getDocMarkup());
18178 var dbody = (this.doc.body || this.doc.documentElement);
18179 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18180 // this copies styles from the containing element into thsi one..
18181 // not sure why we need all of this..
18182 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18184 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18185 //ss['background-attachment'] = 'fixed'; // w3c
18186 dbody.bgProperties = 'fixed'; // ie
18187 //Roo.DomHelper.applyStyles(dbody, ss);
18188 Roo.EventManager.on(this.doc, {
18189 //'mousedown': this.onEditorEvent,
18190 'mouseup': this.onEditorEvent,
18191 'dblclick': this.onEditorEvent,
18192 'click': this.onEditorEvent,
18193 'keyup': this.onEditorEvent,
18198 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18200 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18201 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18203 this.initialized = true;
18205 this.owner.fireEvent('initialize', this);
18210 onDestroy : function(){
18216 //for (var i =0; i < this.toolbars.length;i++) {
18217 // // fixme - ask toolbars for heights?
18218 // this.toolbars[i].onDestroy();
18221 //this.wrap.dom.innerHTML = '';
18222 //this.wrap.remove();
18227 onFirstFocus : function(){
18229 this.assignDocWin();
18232 this.activated = true;
18235 if(Roo.isGecko){ // prevent silly gecko errors
18237 var s = this.win.getSelection();
18238 if(!s.focusNode || s.focusNode.nodeType != 3){
18239 var r = s.getRangeAt(0);
18240 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18245 this.execCmd('useCSS', true);
18246 this.execCmd('styleWithCSS', false);
18249 this.owner.fireEvent('activate', this);
18253 adjustFont: function(btn){
18254 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18255 //if(Roo.isSafari){ // safari
18258 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18259 if(Roo.isSafari){ // safari
18260 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18261 v = (v < 10) ? 10 : v;
18262 v = (v > 48) ? 48 : v;
18263 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18268 v = Math.max(1, v+adjust);
18270 this.execCmd('FontSize', v );
18273 onEditorEvent : function(e){
18274 this.owner.fireEvent('editorevent', this, e);
18275 // this.updateToolbar();
18276 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18279 insertTag : function(tg)
18281 // could be a bit smarter... -> wrap the current selected tRoo..
18282 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18284 range = this.createRange(this.getSelection());
18285 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18286 wrappingNode.appendChild(range.extractContents());
18287 range.insertNode(wrappingNode);
18294 this.execCmd("formatblock", tg);
18298 insertText : function(txt)
18302 var range = this.createRange();
18303 range.deleteContents();
18304 //alert(Sender.getAttribute('label'));
18306 range.insertNode(this.doc.createTextNode(txt));
18312 * Executes a Midas editor command on the editor document and performs necessary focus and
18313 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18314 * @param {String} cmd The Midas command
18315 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18317 relayCmd : function(cmd, value){
18319 this.execCmd(cmd, value);
18320 this.owner.fireEvent('editorevent', this);
18321 //this.updateToolbar();
18322 this.owner.deferFocus();
18326 * Executes a Midas editor command directly on the editor document.
18327 * For visual commands, you should use {@link #relayCmd} instead.
18328 * <b>This should only be called after the editor is initialized.</b>
18329 * @param {String} cmd The Midas command
18330 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18332 execCmd : function(cmd, value){
18333 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18340 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18342 * @param {String} text | dom node..
18344 insertAtCursor : function(text)
18349 if(!this.activated){
18355 var r = this.doc.selection.createRange();
18366 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18370 // from jquery ui (MIT licenced)
18372 var win = this.win;
18374 if (win.getSelection && win.getSelection().getRangeAt) {
18375 range = win.getSelection().getRangeAt(0);
18376 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18377 range.insertNode(node);
18378 } else if (win.document.selection && win.document.selection.createRange) {
18379 // no firefox support
18380 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18381 win.document.selection.createRange().pasteHTML(txt);
18383 // no firefox support
18384 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18385 this.execCmd('InsertHTML', txt);
18394 mozKeyPress : function(e){
18396 var c = e.getCharCode(), cmd;
18399 c = String.fromCharCode(c).toLowerCase();
18413 this.cleanUpPaste.defer(100, this);
18421 e.preventDefault();
18429 fixKeys : function(){ // load time branching for fastest keydown performance
18431 return function(e){
18432 var k = e.getKey(), r;
18435 r = this.doc.selection.createRange();
18438 r.pasteHTML('    ');
18445 r = this.doc.selection.createRange();
18447 var target = r.parentElement();
18448 if(!target || target.tagName.toLowerCase() != 'li'){
18450 r.pasteHTML('<br />');
18456 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18457 this.cleanUpPaste.defer(100, this);
18463 }else if(Roo.isOpera){
18464 return function(e){
18465 var k = e.getKey();
18469 this.execCmd('InsertHTML','    ');
18472 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18473 this.cleanUpPaste.defer(100, this);
18478 }else if(Roo.isSafari){
18479 return function(e){
18480 var k = e.getKey();
18484 this.execCmd('InsertText','\t');
18488 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18489 this.cleanUpPaste.defer(100, this);
18497 getAllAncestors: function()
18499 var p = this.getSelectedNode();
18502 a.push(p); // push blank onto stack..
18503 p = this.getParentElement();
18507 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18511 a.push(this.doc.body);
18515 lastSelNode : false,
18518 getSelection : function()
18520 this.assignDocWin();
18521 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18524 getSelectedNode: function()
18526 // this may only work on Gecko!!!
18528 // should we cache this!!!!
18533 var range = this.createRange(this.getSelection()).cloneRange();
18536 var parent = range.parentElement();
18538 var testRange = range.duplicate();
18539 testRange.moveToElementText(parent);
18540 if (testRange.inRange(range)) {
18543 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18546 parent = parent.parentElement;
18551 // is ancestor a text element.
18552 var ac = range.commonAncestorContainer;
18553 if (ac.nodeType == 3) {
18554 ac = ac.parentNode;
18557 var ar = ac.childNodes;
18560 var other_nodes = [];
18561 var has_other_nodes = false;
18562 for (var i=0;i<ar.length;i++) {
18563 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18566 // fullly contained node.
18568 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18573 // probably selected..
18574 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18575 other_nodes.push(ar[i]);
18579 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18584 has_other_nodes = true;
18586 if (!nodes.length && other_nodes.length) {
18587 nodes= other_nodes;
18589 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18595 createRange: function(sel)
18597 // this has strange effects when using with
18598 // top toolbar - not sure if it's a great idea.
18599 //this.editor.contentWindow.focus();
18600 if (typeof sel != "undefined") {
18602 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18604 return this.doc.createRange();
18607 return this.doc.createRange();
18610 getParentElement: function()
18613 this.assignDocWin();
18614 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18616 var range = this.createRange(sel);
18619 var p = range.commonAncestorContainer;
18620 while (p.nodeType == 3) { // text node
18631 * Range intersection.. the hard stuff...
18635 * [ -- selected range --- ]
18639 * if end is before start or hits it. fail.
18640 * if start is after end or hits it fail.
18642 * if either hits (but other is outside. - then it's not
18648 // @see http://www.thismuchiknow.co.uk/?p=64.
18649 rangeIntersectsNode : function(range, node)
18651 var nodeRange = node.ownerDocument.createRange();
18653 nodeRange.selectNode(node);
18655 nodeRange.selectNodeContents(node);
18658 var rangeStartRange = range.cloneRange();
18659 rangeStartRange.collapse(true);
18661 var rangeEndRange = range.cloneRange();
18662 rangeEndRange.collapse(false);
18664 var nodeStartRange = nodeRange.cloneRange();
18665 nodeStartRange.collapse(true);
18667 var nodeEndRange = nodeRange.cloneRange();
18668 nodeEndRange.collapse(false);
18670 return rangeStartRange.compareBoundaryPoints(
18671 Range.START_TO_START, nodeEndRange) == -1 &&
18672 rangeEndRange.compareBoundaryPoints(
18673 Range.START_TO_START, nodeStartRange) == 1;
18677 rangeCompareNode : function(range, node)
18679 var nodeRange = node.ownerDocument.createRange();
18681 nodeRange.selectNode(node);
18683 nodeRange.selectNodeContents(node);
18687 range.collapse(true);
18689 nodeRange.collapse(true);
18691 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18692 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18694 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18696 var nodeIsBefore = ss == 1;
18697 var nodeIsAfter = ee == -1;
18699 if (nodeIsBefore && nodeIsAfter)
18701 if (!nodeIsBefore && nodeIsAfter)
18702 return 1; //right trailed.
18704 if (nodeIsBefore && !nodeIsAfter)
18705 return 2; // left trailed.
18710 // private? - in a new class?
18711 cleanUpPaste : function()
18713 // cleans up the whole document..
18714 Roo.log('cleanuppaste');
18716 this.cleanUpChildren(this.doc.body);
18717 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18718 if (clean != this.doc.body.innerHTML) {
18719 this.doc.body.innerHTML = clean;
18724 cleanWordChars : function(input) {// change the chars to hex code
18725 var he = Roo.HtmlEditorCore;
18727 var output = input;
18728 Roo.each(he.swapCodes, function(sw) {
18729 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18731 output = output.replace(swapper, sw[1]);
18738 cleanUpChildren : function (n)
18740 if (!n.childNodes.length) {
18743 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18744 this.cleanUpChild(n.childNodes[i]);
18751 cleanUpChild : function (node)
18754 //console.log(node);
18755 if (node.nodeName == "#text") {
18756 // clean up silly Windows -- stuff?
18759 if (node.nodeName == "#comment") {
18760 node.parentNode.removeChild(node);
18761 // clean up silly Windows -- stuff?
18764 var lcname = node.tagName.toLowerCase();
18765 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18766 // whitelist of tags..
18768 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18770 node.parentNode.removeChild(node);
18775 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18777 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18778 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18780 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18781 // remove_keep_children = true;
18784 if (remove_keep_children) {
18785 this.cleanUpChildren(node);
18786 // inserts everything just before this node...
18787 while (node.childNodes.length) {
18788 var cn = node.childNodes[0];
18789 node.removeChild(cn);
18790 node.parentNode.insertBefore(cn, node);
18792 node.parentNode.removeChild(node);
18796 if (!node.attributes || !node.attributes.length) {
18797 this.cleanUpChildren(node);
18801 function cleanAttr(n,v)
18804 if (v.match(/^\./) || v.match(/^\//)) {
18807 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18810 if (v.match(/^#/)) {
18813 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18814 node.removeAttribute(n);
18818 var cwhite = this.cwhite;
18819 var cblack = this.cblack;
18821 function cleanStyle(n,v)
18823 if (v.match(/expression/)) { //XSS?? should we even bother..
18824 node.removeAttribute(n);
18828 var parts = v.split(/;/);
18831 Roo.each(parts, function(p) {
18832 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18836 var l = p.split(':').shift().replace(/\s+/g,'');
18837 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18839 if ( cwhite.length && cblack.indexOf(l) > -1) {
18840 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18841 //node.removeAttribute(n);
18845 // only allow 'c whitelisted system attributes'
18846 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18847 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18848 //node.removeAttribute(n);
18858 if (clean.length) {
18859 node.setAttribute(n, clean.join(';'));
18861 node.removeAttribute(n);
18867 for (var i = node.attributes.length-1; i > -1 ; i--) {
18868 var a = node.attributes[i];
18871 if (a.name.toLowerCase().substr(0,2)=='on') {
18872 node.removeAttribute(a.name);
18875 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18876 node.removeAttribute(a.name);
18879 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18880 cleanAttr(a.name,a.value); // fixme..
18883 if (a.name == 'style') {
18884 cleanStyle(a.name,a.value);
18887 /// clean up MS crap..
18888 // tecnically this should be a list of valid class'es..
18891 if (a.name == 'class') {
18892 if (a.value.match(/^Mso/)) {
18893 node.className = '';
18896 if (a.value.match(/body/)) {
18897 node.className = '';
18908 this.cleanUpChildren(node);
18913 * Clean up MS wordisms...
18915 cleanWord : function(node)
18918 var cleanWordChildren = function()
18920 if (!node.childNodes.length) {
18923 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18924 _t.cleanWord(node.childNodes[i]);
18930 this.cleanWord(this.doc.body);
18933 if (node.nodeName == "#text") {
18934 // clean up silly Windows -- stuff?
18937 if (node.nodeName == "#comment") {
18938 node.parentNode.removeChild(node);
18939 // clean up silly Windows -- stuff?
18943 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18944 node.parentNode.removeChild(node);
18948 // remove - but keep children..
18949 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18950 while (node.childNodes.length) {
18951 var cn = node.childNodes[0];
18952 node.removeChild(cn);
18953 node.parentNode.insertBefore(cn, node);
18955 node.parentNode.removeChild(node);
18956 cleanWordChildren();
18960 if (node.className.length) {
18962 var cn = node.className.split(/\W+/);
18964 Roo.each(cn, function(cls) {
18965 if (cls.match(/Mso[a-zA-Z]+/)) {
18970 node.className = cna.length ? cna.join(' ') : '';
18972 node.removeAttribute("class");
18976 if (node.hasAttribute("lang")) {
18977 node.removeAttribute("lang");
18980 if (node.hasAttribute("style")) {
18982 var styles = node.getAttribute("style").split(";");
18984 Roo.each(styles, function(s) {
18985 if (!s.match(/:/)) {
18988 var kv = s.split(":");
18989 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18992 // what ever is left... we allow.
18995 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18996 if (!nstyle.length) {
18997 node.removeAttribute('style');
19001 cleanWordChildren();
19005 domToHTML : function(currentElement, depth, nopadtext) {
19007 depth = depth || 0;
19008 nopadtext = nopadtext || false;
19010 if (!currentElement) {
19011 return this.domToHTML(this.doc.body);
19014 //Roo.log(currentElement);
19016 var allText = false;
19017 var nodeName = currentElement.nodeName;
19018 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19020 if (nodeName == '#text') {
19022 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19027 if (nodeName != 'BODY') {
19030 // Prints the node tagName, such as <A>, <IMG>, etc
19033 for(i = 0; i < currentElement.attributes.length;i++) {
19035 var aname = currentElement.attributes.item(i).name;
19036 if (!currentElement.attributes.item(i).value.length) {
19039 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19042 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19051 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19054 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19059 // Traverse the tree
19061 var currentElementChild = currentElement.childNodes.item(i);
19062 var allText = true;
19063 var innerHTML = '';
19065 while (currentElementChild) {
19066 // Formatting code (indent the tree so it looks nice on the screen)
19067 var nopad = nopadtext;
19068 if (lastnode == 'SPAN') {
19072 if (currentElementChild.nodeName == '#text') {
19073 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19074 toadd = nopadtext ? toadd : toadd.trim();
19075 if (!nopad && toadd.length > 80) {
19076 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19078 innerHTML += toadd;
19081 currentElementChild = currentElement.childNodes.item(i);
19087 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19089 // Recursively traverse the tree structure of the child node
19090 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19091 lastnode = currentElementChild.nodeName;
19093 currentElementChild=currentElement.childNodes.item(i);
19099 // The remaining code is mostly for formatting the tree
19100 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19105 ret+= "</"+tagName+">";
19111 applyBlacklists : function()
19113 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19114 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19118 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19119 if (b.indexOf(tag) > -1) {
19122 this.white.push(tag);
19126 Roo.each(w, function(tag) {
19127 if (b.indexOf(tag) > -1) {
19130 if (this.white.indexOf(tag) > -1) {
19133 this.white.push(tag);
19138 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19139 if (w.indexOf(tag) > -1) {
19142 this.black.push(tag);
19146 Roo.each(b, function(tag) {
19147 if (w.indexOf(tag) > -1) {
19150 if (this.black.indexOf(tag) > -1) {
19153 this.black.push(tag);
19158 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19159 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19163 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19164 if (b.indexOf(tag) > -1) {
19167 this.cwhite.push(tag);
19171 Roo.each(w, function(tag) {
19172 if (b.indexOf(tag) > -1) {
19175 if (this.cwhite.indexOf(tag) > -1) {
19178 this.cwhite.push(tag);
19183 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19184 if (w.indexOf(tag) > -1) {
19187 this.cblack.push(tag);
19191 Roo.each(b, function(tag) {
19192 if (w.indexOf(tag) > -1) {
19195 if (this.cblack.indexOf(tag) > -1) {
19198 this.cblack.push(tag);
19203 setStylesheets : function(stylesheets)
19205 if(typeof(stylesheets) == 'string'){
19206 Roo.get(this.iframe.contentDocument.head).createChild({
19208 rel : 'stylesheet',
19217 Roo.each(stylesheets, function(s) {
19222 Roo.get(_this.iframe.contentDocument.head).createChild({
19224 rel : 'stylesheet',
19233 removeStylesheets : function()
19237 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19242 // hide stuff that is not compatible
19256 * @event specialkey
19260 * @cfg {String} fieldClass @hide
19263 * @cfg {String} focusClass @hide
19266 * @cfg {String} autoCreate @hide
19269 * @cfg {String} inputType @hide
19272 * @cfg {String} invalidClass @hide
19275 * @cfg {String} invalidText @hide
19278 * @cfg {String} msgFx @hide
19281 * @cfg {String} validateOnBlur @hide
19285 Roo.HtmlEditorCore.white = [
19286 'area', 'br', 'img', 'input', 'hr', 'wbr',
19288 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19289 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19290 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19291 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19292 'table', 'ul', 'xmp',
19294 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19297 'dir', 'menu', 'ol', 'ul', 'dl',
19303 Roo.HtmlEditorCore.black = [
19304 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19306 'base', 'basefont', 'bgsound', 'blink', 'body',
19307 'frame', 'frameset', 'head', 'html', 'ilayer',
19308 'iframe', 'layer', 'link', 'meta', 'object',
19309 'script', 'style' ,'title', 'xml' // clean later..
19311 Roo.HtmlEditorCore.clean = [
19312 'script', 'style', 'title', 'xml'
19314 Roo.HtmlEditorCore.remove = [
19319 Roo.HtmlEditorCore.ablack = [
19323 Roo.HtmlEditorCore.aclean = [
19324 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19328 Roo.HtmlEditorCore.pwhite= [
19329 'http', 'https', 'mailto'
19332 // white listed style attributes.
19333 Roo.HtmlEditorCore.cwhite= [
19334 // 'text-align', /// default is to allow most things..
19340 // black listed style attributes.
19341 Roo.HtmlEditorCore.cblack= [
19342 // 'font-size' -- this can be set by the project
19346 Roo.HtmlEditorCore.swapCodes =[
19365 * @class Roo.bootstrap.HtmlEditor
19366 * @extends Roo.bootstrap.TextArea
19367 * Bootstrap HtmlEditor class
19370 * Create a new HtmlEditor
19371 * @param {Object} config The config object
19374 Roo.bootstrap.HtmlEditor = function(config){
19375 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19376 if (!this.toolbars) {
19377 this.toolbars = [];
19379 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19382 * @event initialize
19383 * Fires when the editor is fully initialized (including the iframe)
19384 * @param {HtmlEditor} this
19389 * Fires when the editor is first receives the focus. Any insertion must wait
19390 * until after this event.
19391 * @param {HtmlEditor} this
19395 * @event beforesync
19396 * Fires before the textarea is updated with content from the editor iframe. Return false
19397 * to cancel the sync.
19398 * @param {HtmlEditor} this
19399 * @param {String} html
19403 * @event beforepush
19404 * Fires before the iframe editor is updated with content from the textarea. Return false
19405 * to cancel the push.
19406 * @param {HtmlEditor} this
19407 * @param {String} html
19412 * Fires when the textarea is updated with content from the editor iframe.
19413 * @param {HtmlEditor} this
19414 * @param {String} html
19419 * Fires when the iframe editor is updated with content from the textarea.
19420 * @param {HtmlEditor} this
19421 * @param {String} html
19425 * @event editmodechange
19426 * Fires when the editor switches edit modes
19427 * @param {HtmlEditor} this
19428 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19430 editmodechange: true,
19432 * @event editorevent
19433 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19434 * @param {HtmlEditor} this
19438 * @event firstfocus
19439 * Fires when on first focus - needed by toolbars..
19440 * @param {HtmlEditor} this
19445 * Auto save the htmlEditor value as a file into Events
19446 * @param {HtmlEditor} this
19450 * @event savedpreview
19451 * preview the saved version of htmlEditor
19452 * @param {HtmlEditor} this
19459 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19463 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19468 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19473 * @cfg {Number} height (in pixels)
19477 * @cfg {Number} width (in pixels)
19482 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19485 stylesheets: false,
19490 // private properties
19491 validationEvent : false,
19493 initialized : false,
19496 onFocus : Roo.emptyFn,
19498 hideMode:'offsets',
19501 tbContainer : false,
19503 toolbarContainer :function() {
19504 return this.wrap.select('.x-html-editor-tb',true).first();
19508 * Protected method that will not generally be called directly. It
19509 * is called when the editor creates its toolbar. Override this method if you need to
19510 * add custom toolbar buttons.
19511 * @param {HtmlEditor} editor
19513 createToolbar : function(){
19515 Roo.log("create toolbars");
19517 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19518 this.toolbars[0].render(this.toolbarContainer());
19522 // if (!editor.toolbars || !editor.toolbars.length) {
19523 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19526 // for (var i =0 ; i < editor.toolbars.length;i++) {
19527 // editor.toolbars[i] = Roo.factory(
19528 // typeof(editor.toolbars[i]) == 'string' ?
19529 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19530 // Roo.bootstrap.HtmlEditor);
19531 // editor.toolbars[i].init(editor);
19537 onRender : function(ct, position)
19539 // Roo.log("Call onRender: " + this.xtype);
19541 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19543 this.wrap = this.inputEl().wrap({
19544 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19547 this.editorcore.onRender(ct, position);
19549 if (this.resizable) {
19550 this.resizeEl = new Roo.Resizable(this.wrap, {
19554 minHeight : this.height,
19555 height: this.height,
19556 handles : this.resizable,
19559 resize : function(r, w, h) {
19560 _t.onResize(w,h); // -something
19566 this.createToolbar(this);
19569 if(!this.width && this.resizable){
19570 this.setSize(this.wrap.getSize());
19572 if (this.resizeEl) {
19573 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19574 // should trigger onReize..
19580 onResize : function(w, h)
19582 Roo.log('resize: ' +w + ',' + h );
19583 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19587 if(this.inputEl() ){
19588 if(typeof w == 'number'){
19589 var aw = w - this.wrap.getFrameWidth('lr');
19590 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19593 if(typeof h == 'number'){
19594 var tbh = -11; // fixme it needs to tool bar size!
19595 for (var i =0; i < this.toolbars.length;i++) {
19596 // fixme - ask toolbars for heights?
19597 tbh += this.toolbars[i].el.getHeight();
19598 //if (this.toolbars[i].footer) {
19599 // tbh += this.toolbars[i].footer.el.getHeight();
19607 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19608 ah -= 5; // knock a few pixes off for look..
19609 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19613 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19614 this.editorcore.onResize(ew,eh);
19619 * Toggles the editor between standard and source edit mode.
19620 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19622 toggleSourceEdit : function(sourceEditMode)
19624 this.editorcore.toggleSourceEdit(sourceEditMode);
19626 if(this.editorcore.sourceEditMode){
19627 Roo.log('editor - showing textarea');
19630 // Roo.log(this.syncValue());
19632 this.inputEl().removeClass(['hide', 'x-hidden']);
19633 this.inputEl().dom.removeAttribute('tabIndex');
19634 this.inputEl().focus();
19636 Roo.log('editor - hiding textarea');
19638 // Roo.log(this.pushValue());
19641 this.inputEl().addClass(['hide', 'x-hidden']);
19642 this.inputEl().dom.setAttribute('tabIndex', -1);
19643 //this.deferFocus();
19646 if(this.resizable){
19647 this.setSize(this.wrap.getSize());
19650 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19653 // private (for BoxComponent)
19654 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19656 // private (for BoxComponent)
19657 getResizeEl : function(){
19661 // private (for BoxComponent)
19662 getPositionEl : function(){
19667 initEvents : function(){
19668 this.originalValue = this.getValue();
19672 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19675 // markInvalid : Roo.emptyFn,
19677 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19680 // clearInvalid : Roo.emptyFn,
19682 setValue : function(v){
19683 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19684 this.editorcore.pushValue();
19689 deferFocus : function(){
19690 this.focus.defer(10, this);
19694 focus : function(){
19695 this.editorcore.focus();
19701 onDestroy : function(){
19707 for (var i =0; i < this.toolbars.length;i++) {
19708 // fixme - ask toolbars for heights?
19709 this.toolbars[i].onDestroy();
19712 this.wrap.dom.innerHTML = '';
19713 this.wrap.remove();
19718 onFirstFocus : function(){
19719 //Roo.log("onFirstFocus");
19720 this.editorcore.onFirstFocus();
19721 for (var i =0; i < this.toolbars.length;i++) {
19722 this.toolbars[i].onFirstFocus();
19728 syncValue : function()
19730 this.editorcore.syncValue();
19733 pushValue : function()
19735 this.editorcore.pushValue();
19739 // hide stuff that is not compatible
19753 * @event specialkey
19757 * @cfg {String} fieldClass @hide
19760 * @cfg {String} focusClass @hide
19763 * @cfg {String} autoCreate @hide
19766 * @cfg {String} inputType @hide
19769 * @cfg {String} invalidClass @hide
19772 * @cfg {String} invalidText @hide
19775 * @cfg {String} msgFx @hide
19778 * @cfg {String} validateOnBlur @hide
19787 Roo.namespace('Roo.bootstrap.htmleditor');
19789 * @class Roo.bootstrap.HtmlEditorToolbar1
19794 new Roo.bootstrap.HtmlEditor({
19797 new Roo.bootstrap.HtmlEditorToolbar1({
19798 disable : { fonts: 1 , format: 1, ..., ... , ...],
19804 * @cfg {Object} disable List of elements to disable..
19805 * @cfg {Array} btns List of additional buttons.
19809 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19812 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19815 Roo.apply(this, config);
19817 // default disabled, based on 'good practice'..
19818 this.disable = this.disable || {};
19819 Roo.applyIf(this.disable, {
19822 specialElements : true
19824 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19826 this.editor = config.editor;
19827 this.editorcore = config.editor.editorcore;
19829 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19831 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19832 // dont call parent... till later.
19834 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19839 editorcore : false,
19844 "h1","h2","h3","h4","h5","h6",
19846 "abbr", "acronym", "address", "cite", "samp", "var",
19850 onRender : function(ct, position)
19852 // Roo.log("Call onRender: " + this.xtype);
19854 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19856 this.el.dom.style.marginBottom = '0';
19858 var editorcore = this.editorcore;
19859 var editor= this.editor;
19862 var btn = function(id,cmd , toggle, handler){
19864 var event = toggle ? 'toggle' : 'click';
19869 xns: Roo.bootstrap,
19872 enableToggle:toggle !== false,
19874 pressed : toggle ? false : null,
19877 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19878 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19887 xns: Roo.bootstrap,
19888 glyphicon : 'font',
19892 xns: Roo.bootstrap,
19896 Roo.each(this.formats, function(f) {
19897 style.menu.items.push({
19899 xns: Roo.bootstrap,
19900 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19905 editorcore.insertTag(this.tagname);
19912 children.push(style);
19915 btn('bold',false,true);
19916 btn('italic',false,true);
19917 btn('align-left', 'justifyleft',true);
19918 btn('align-center', 'justifycenter',true);
19919 btn('align-right' , 'justifyright',true);
19920 btn('link', false, false, function(btn) {
19921 //Roo.log("create link?");
19922 var url = prompt(this.createLinkText, this.defaultLinkValue);
19923 if(url && url != 'http:/'+'/'){
19924 this.editorcore.relayCmd('createlink', url);
19927 btn('list','insertunorderedlist',true);
19928 btn('pencil', false,true, function(btn){
19931 this.toggleSourceEdit(btn.pressed);
19937 xns: Roo.bootstrap,
19942 xns: Roo.bootstrap,
19947 cog.menu.items.push({
19949 xns: Roo.bootstrap,
19950 html : Clean styles,
19955 editorcore.insertTag(this.tagname);
19964 this.xtype = 'NavSimplebar';
19966 for(var i=0;i< children.length;i++) {
19968 this.buttons.add(this.addxtypeChild(children[i]));
19972 editor.on('editorevent', this.updateToolbar, this);
19974 onBtnClick : function(id)
19976 this.editorcore.relayCmd(id);
19977 this.editorcore.focus();
19981 * Protected method that will not generally be called directly. It triggers
19982 * a toolbar update by reading the markup state of the current selection in the editor.
19984 updateToolbar: function(){
19986 if(!this.editorcore.activated){
19987 this.editor.onFirstFocus(); // is this neeed?
19991 var btns = this.buttons;
19992 var doc = this.editorcore.doc;
19993 btns.get('bold').setActive(doc.queryCommandState('bold'));
19994 btns.get('italic').setActive(doc.queryCommandState('italic'));
19995 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19997 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19998 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19999 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20001 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20002 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20005 var ans = this.editorcore.getAllAncestors();
20006 if (this.formatCombo) {
20009 var store = this.formatCombo.store;
20010 this.formatCombo.setValue("");
20011 for (var i =0; i < ans.length;i++) {
20012 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20014 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20022 // hides menus... - so this cant be on a menu...
20023 Roo.bootstrap.MenuMgr.hideAll();
20025 Roo.bootstrap.MenuMgr.hideAll();
20026 //this.editorsyncValue();
20028 onFirstFocus: function() {
20029 this.buttons.each(function(item){
20033 toggleSourceEdit : function(sourceEditMode){
20036 if(sourceEditMode){
20037 Roo.log("disabling buttons");
20038 this.buttons.each( function(item){
20039 if(item.cmd != 'pencil'){
20045 Roo.log("enabling buttons");
20046 if(this.editorcore.initialized){
20047 this.buttons.each( function(item){
20053 Roo.log("calling toggole on editor");
20054 // tell the editor that it's been pressed..
20055 this.editor.toggleSourceEdit(sourceEditMode);
20065 * @class Roo.bootstrap.Table.AbstractSelectionModel
20066 * @extends Roo.util.Observable
20067 * Abstract base class for grid SelectionModels. It provides the interface that should be
20068 * implemented by descendant classes. This class should not be directly instantiated.
20071 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20072 this.locked = false;
20073 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20077 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20078 /** @ignore Called by the grid automatically. Do not call directly. */
20079 init : function(grid){
20085 * Locks the selections.
20088 this.locked = true;
20092 * Unlocks the selections.
20094 unlock : function(){
20095 this.locked = false;
20099 * Returns true if the selections are locked.
20100 * @return {Boolean}
20102 isLocked : function(){
20103 return this.locked;
20107 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20108 * @class Roo.bootstrap.Table.RowSelectionModel
20109 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20110 * It supports multiple selections and keyboard selection/navigation.
20112 * @param {Object} config
20115 Roo.bootstrap.Table.RowSelectionModel = function(config){
20116 Roo.apply(this, config);
20117 this.selections = new Roo.util.MixedCollection(false, function(o){
20122 this.lastActive = false;
20126 * @event selectionchange
20127 * Fires when the selection changes
20128 * @param {SelectionModel} this
20130 "selectionchange" : true,
20132 * @event afterselectionchange
20133 * Fires after the selection changes (eg. by key press or clicking)
20134 * @param {SelectionModel} this
20136 "afterselectionchange" : true,
20138 * @event beforerowselect
20139 * Fires when a row is selected being selected, return false to cancel.
20140 * @param {SelectionModel} this
20141 * @param {Number} rowIndex The selected index
20142 * @param {Boolean} keepExisting False if other selections will be cleared
20144 "beforerowselect" : true,
20147 * Fires when a row is selected.
20148 * @param {SelectionModel} this
20149 * @param {Number} rowIndex The selected index
20150 * @param {Roo.data.Record} r The record
20152 "rowselect" : true,
20154 * @event rowdeselect
20155 * Fires when a row is deselected.
20156 * @param {SelectionModel} this
20157 * @param {Number} rowIndex The selected index
20159 "rowdeselect" : true
20161 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20162 this.locked = false;
20165 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20167 * @cfg {Boolean} singleSelect
20168 * True to allow selection of only one row at a time (defaults to false)
20170 singleSelect : false,
20173 initEvents : function(){
20175 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20176 this.grid.on("mousedown", this.handleMouseDown, this);
20177 }else{ // allow click to work like normal
20178 this.grid.on("rowclick", this.handleDragableRowClick, this);
20181 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20182 "up" : function(e){
20184 this.selectPrevious(e.shiftKey);
20185 }else if(this.last !== false && this.lastActive !== false){
20186 var last = this.last;
20187 this.selectRange(this.last, this.lastActive-1);
20188 this.grid.getView().focusRow(this.lastActive);
20189 if(last !== false){
20193 this.selectFirstRow();
20195 this.fireEvent("afterselectionchange", this);
20197 "down" : function(e){
20199 this.selectNext(e.shiftKey);
20200 }else if(this.last !== false && this.lastActive !== false){
20201 var last = this.last;
20202 this.selectRange(this.last, this.lastActive+1);
20203 this.grid.getView().focusRow(this.lastActive);
20204 if(last !== false){
20208 this.selectFirstRow();
20210 this.fireEvent("afterselectionchange", this);
20215 var view = this.grid.view;
20216 view.on("refresh", this.onRefresh, this);
20217 view.on("rowupdated", this.onRowUpdated, this);
20218 view.on("rowremoved", this.onRemove, this);
20222 onRefresh : function(){
20223 var ds = this.grid.dataSource, i, v = this.grid.view;
20224 var s = this.selections;
20225 s.each(function(r){
20226 if((i = ds.indexOfId(r.id)) != -1){
20235 onRemove : function(v, index, r){
20236 this.selections.remove(r);
20240 onRowUpdated : function(v, index, r){
20241 if(this.isSelected(r)){
20242 v.onRowSelect(index);
20248 * @param {Array} records The records to select
20249 * @param {Boolean} keepExisting (optional) True to keep existing selections
20251 selectRecords : function(records, keepExisting){
20253 this.clearSelections();
20255 var ds = this.grid.dataSource;
20256 for(var i = 0, len = records.length; i < len; i++){
20257 this.selectRow(ds.indexOf(records[i]), true);
20262 * Gets the number of selected rows.
20265 getCount : function(){
20266 return this.selections.length;
20270 * Selects the first row in the grid.
20272 selectFirstRow : function(){
20277 * Select the last row.
20278 * @param {Boolean} keepExisting (optional) True to keep existing selections
20280 selectLastRow : function(keepExisting){
20281 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20285 * Selects the row immediately following the last selected row.
20286 * @param {Boolean} keepExisting (optional) True to keep existing selections
20288 selectNext : function(keepExisting){
20289 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20290 this.selectRow(this.last+1, keepExisting);
20291 this.grid.getView().focusRow(this.last);
20296 * Selects the row that precedes the last selected row.
20297 * @param {Boolean} keepExisting (optional) True to keep existing selections
20299 selectPrevious : function(keepExisting){
20301 this.selectRow(this.last-1, keepExisting);
20302 this.grid.getView().focusRow(this.last);
20307 * Returns the selected records
20308 * @return {Array} Array of selected records
20310 getSelections : function(){
20311 return [].concat(this.selections.items);
20315 * Returns the first selected record.
20318 getSelected : function(){
20319 return this.selections.itemAt(0);
20324 * Clears all selections.
20326 clearSelections : function(fast){
20327 if(this.locked) return;
20329 var ds = this.grid.dataSource;
20330 var s = this.selections;
20331 s.each(function(r){
20332 this.deselectRow(ds.indexOfId(r.id));
20336 this.selections.clear();
20343 * Selects all rows.
20345 selectAll : function(){
20346 if(this.locked) return;
20347 this.selections.clear();
20348 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20349 this.selectRow(i, true);
20354 * Returns True if there is a selection.
20355 * @return {Boolean}
20357 hasSelection : function(){
20358 return this.selections.length > 0;
20362 * Returns True if the specified row is selected.
20363 * @param {Number/Record} record The record or index of the record to check
20364 * @return {Boolean}
20366 isSelected : function(index){
20367 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20368 return (r && this.selections.key(r.id) ? true : false);
20372 * Returns True if the specified record id is selected.
20373 * @param {String} id The id of record to check
20374 * @return {Boolean}
20376 isIdSelected : function(id){
20377 return (this.selections.key(id) ? true : false);
20381 handleMouseDown : function(e, t){
20382 var view = this.grid.getView(), rowIndex;
20383 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20386 if(e.shiftKey && this.last !== false){
20387 var last = this.last;
20388 this.selectRange(last, rowIndex, e.ctrlKey);
20389 this.last = last; // reset the last
20390 view.focusRow(rowIndex);
20392 var isSelected = this.isSelected(rowIndex);
20393 if(e.button !== 0 && isSelected){
20394 view.focusRow(rowIndex);
20395 }else if(e.ctrlKey && isSelected){
20396 this.deselectRow(rowIndex);
20397 }else if(!isSelected){
20398 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20399 view.focusRow(rowIndex);
20402 this.fireEvent("afterselectionchange", this);
20405 handleDragableRowClick : function(grid, rowIndex, e)
20407 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20408 this.selectRow(rowIndex, false);
20409 grid.view.focusRow(rowIndex);
20410 this.fireEvent("afterselectionchange", this);
20415 * Selects multiple rows.
20416 * @param {Array} rows Array of the indexes of the row to select
20417 * @param {Boolean} keepExisting (optional) True to keep existing selections
20419 selectRows : function(rows, keepExisting){
20421 this.clearSelections();
20423 for(var i = 0, len = rows.length; i < len; i++){
20424 this.selectRow(rows[i], true);
20429 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20430 * @param {Number} startRow The index of the first row in the range
20431 * @param {Number} endRow The index of the last row in the range
20432 * @param {Boolean} keepExisting (optional) True to retain existing selections
20434 selectRange : function(startRow, endRow, keepExisting){
20435 if(this.locked) return;
20437 this.clearSelections();
20439 if(startRow <= endRow){
20440 for(var i = startRow; i <= endRow; i++){
20441 this.selectRow(i, true);
20444 for(var i = startRow; i >= endRow; i--){
20445 this.selectRow(i, true);
20451 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20452 * @param {Number} startRow The index of the first row in the range
20453 * @param {Number} endRow The index of the last row in the range
20455 deselectRange : function(startRow, endRow, preventViewNotify){
20456 if(this.locked) return;
20457 for(var i = startRow; i <= endRow; i++){
20458 this.deselectRow(i, preventViewNotify);
20464 * @param {Number} row The index of the row to select
20465 * @param {Boolean} keepExisting (optional) True to keep existing selections
20467 selectRow : function(index, keepExisting, preventViewNotify){
20468 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20469 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20470 if(!keepExisting || this.singleSelect){
20471 this.clearSelections();
20473 var r = this.grid.dataSource.getAt(index);
20474 this.selections.add(r);
20475 this.last = this.lastActive = index;
20476 if(!preventViewNotify){
20477 this.grid.getView().onRowSelect(index);
20479 this.fireEvent("rowselect", this, index, r);
20480 this.fireEvent("selectionchange", this);
20486 * @param {Number} row The index of the row to deselect
20488 deselectRow : function(index, preventViewNotify){
20489 if(this.locked) return;
20490 if(this.last == index){
20493 if(this.lastActive == index){
20494 this.lastActive = false;
20496 var r = this.grid.dataSource.getAt(index);
20497 this.selections.remove(r);
20498 if(!preventViewNotify){
20499 this.grid.getView().onRowDeselect(index);
20501 this.fireEvent("rowdeselect", this, index);
20502 this.fireEvent("selectionchange", this);
20506 restoreLast : function(){
20508 this.last = this._last;
20513 acceptsNav : function(row, col, cm){
20514 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20518 onEditorKey : function(field, e){
20519 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20524 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20526 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20528 }else if(k == e.ENTER && !e.ctrlKey){
20532 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20534 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20536 }else if(k == e.ESC){
20540 g.startEditing(newCell[0], newCell[1]);
20545 * Ext JS Library 1.1.1
20546 * Copyright(c) 2006-2007, Ext JS, LLC.
20548 * Originally Released Under LGPL - original licence link has changed is not relivant.
20551 * <script type="text/javascript">
20555 * @class Roo.bootstrap.PagingToolbar
20557 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20559 * Create a new PagingToolbar
20560 * @param {Object} config The config object
20562 Roo.bootstrap.PagingToolbar = function(config)
20564 // old args format still supported... - xtype is prefered..
20565 // created from xtype...
20566 var ds = config.dataSource;
20567 this.toolbarItems = [];
20568 if (config.items) {
20569 this.toolbarItems = config.items;
20570 // config.items = [];
20573 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20580 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20584 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20586 * @cfg {Roo.data.Store} dataSource
20587 * The underlying data store providing the paged data
20590 * @cfg {String/HTMLElement/Element} container
20591 * container The id or element that will contain the toolbar
20594 * @cfg {Boolean} displayInfo
20595 * True to display the displayMsg (defaults to false)
20598 * @cfg {Number} pageSize
20599 * The number of records to display per page (defaults to 20)
20603 * @cfg {String} displayMsg
20604 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20606 displayMsg : 'Displaying {0} - {1} of {2}',
20608 * @cfg {String} emptyMsg
20609 * The message to display when no records are found (defaults to "No data to display")
20611 emptyMsg : 'No data to display',
20613 * Customizable piece of the default paging text (defaults to "Page")
20616 beforePageText : "Page",
20618 * Customizable piece of the default paging text (defaults to "of %0")
20621 afterPageText : "of {0}",
20623 * Customizable piece of the default paging text (defaults to "First Page")
20626 firstText : "First Page",
20628 * Customizable piece of the default paging text (defaults to "Previous Page")
20631 prevText : "Previous Page",
20633 * Customizable piece of the default paging text (defaults to "Next Page")
20636 nextText : "Next Page",
20638 * Customizable piece of the default paging text (defaults to "Last Page")
20641 lastText : "Last Page",
20643 * Customizable piece of the default paging text (defaults to "Refresh")
20646 refreshText : "Refresh",
20650 onRender : function(ct, position)
20652 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20653 this.navgroup.parentId = this.id;
20654 this.navgroup.onRender(this.el, null);
20655 // add the buttons to the navgroup
20657 if(this.displayInfo){
20658 Roo.log(this.el.select('ul.navbar-nav',true).first());
20659 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20660 this.displayEl = this.el.select('.x-paging-info', true).first();
20661 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20662 // this.displayEl = navel.el.select('span',true).first();
20668 Roo.each(_this.buttons, function(e){
20669 Roo.factory(e).onRender(_this.el, null);
20673 Roo.each(_this.toolbarItems, function(e) {
20674 _this.navgroup.addItem(e);
20678 this.first = this.navgroup.addItem({
20679 tooltip: this.firstText,
20681 icon : 'fa fa-backward',
20683 preventDefault: true,
20684 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20687 this.prev = this.navgroup.addItem({
20688 tooltip: this.prevText,
20690 icon : 'fa fa-step-backward',
20692 preventDefault: true,
20693 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20695 //this.addSeparator();
20698 var field = this.navgroup.addItem( {
20700 cls : 'x-paging-position',
20702 html : this.beforePageText +
20703 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20704 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20707 this.field = field.el.select('input', true).first();
20708 this.field.on("keydown", this.onPagingKeydown, this);
20709 this.field.on("focus", function(){this.dom.select();});
20712 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20713 //this.field.setHeight(18);
20714 //this.addSeparator();
20715 this.next = this.navgroup.addItem({
20716 tooltip: this.nextText,
20718 html : ' <i class="fa fa-step-forward">',
20720 preventDefault: true,
20721 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20723 this.last = this.navgroup.addItem({
20724 tooltip: this.lastText,
20725 icon : 'fa fa-forward',
20728 preventDefault: true,
20729 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20731 //this.addSeparator();
20732 this.loading = this.navgroup.addItem({
20733 tooltip: this.refreshText,
20734 icon: 'fa fa-refresh',
20735 preventDefault: true,
20736 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20742 updateInfo : function(){
20743 if(this.displayEl){
20744 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20745 var msg = count == 0 ?
20749 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20751 this.displayEl.update(msg);
20756 onLoad : function(ds, r, o){
20757 this.cursor = o.params ? o.params.start : 0;
20758 var d = this.getPageData(),
20762 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20763 this.field.dom.value = ap;
20764 this.first.setDisabled(ap == 1);
20765 this.prev.setDisabled(ap == 1);
20766 this.next.setDisabled(ap == ps);
20767 this.last.setDisabled(ap == ps);
20768 this.loading.enable();
20773 getPageData : function(){
20774 var total = this.ds.getTotalCount();
20777 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20778 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20783 onLoadError : function(){
20784 this.loading.enable();
20788 onPagingKeydown : function(e){
20789 var k = e.getKey();
20790 var d = this.getPageData();
20792 var v = this.field.dom.value, pageNum;
20793 if(!v || isNaN(pageNum = parseInt(v, 10))){
20794 this.field.dom.value = d.activePage;
20797 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20798 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20801 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))
20803 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20804 this.field.dom.value = pageNum;
20805 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20808 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20810 var v = this.field.dom.value, pageNum;
20811 var increment = (e.shiftKey) ? 10 : 1;
20812 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20814 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20815 this.field.dom.value = d.activePage;
20818 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20820 this.field.dom.value = parseInt(v, 10) + increment;
20821 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20822 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20829 beforeLoad : function(){
20831 this.loading.disable();
20836 onClick : function(which){
20845 ds.load({params:{start: 0, limit: this.pageSize}});
20848 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20851 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20854 var total = ds.getTotalCount();
20855 var extra = total % this.pageSize;
20856 var lastStart = extra ? (total - extra) : total-this.pageSize;
20857 ds.load({params:{start: lastStart, limit: this.pageSize}});
20860 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20866 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20867 * @param {Roo.data.Store} store The data store to unbind
20869 unbind : function(ds){
20870 ds.un("beforeload", this.beforeLoad, this);
20871 ds.un("load", this.onLoad, this);
20872 ds.un("loadexception", this.onLoadError, this);
20873 ds.un("remove", this.updateInfo, this);
20874 ds.un("add", this.updateInfo, this);
20875 this.ds = undefined;
20879 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20880 * @param {Roo.data.Store} store The data store to bind
20882 bind : function(ds){
20883 ds.on("beforeload", this.beforeLoad, this);
20884 ds.on("load", this.onLoad, this);
20885 ds.on("loadexception", this.onLoadError, this);
20886 ds.on("remove", this.updateInfo, this);
20887 ds.on("add", this.updateInfo, this);
20898 * @class Roo.bootstrap.MessageBar
20899 * @extends Roo.bootstrap.Component
20900 * Bootstrap MessageBar class
20901 * @cfg {String} html contents of the MessageBar
20902 * @cfg {String} weight (info | success | warning | danger) default info
20903 * @cfg {String} beforeClass insert the bar before the given class
20904 * @cfg {Boolean} closable (true | false) default false
20905 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20908 * Create a new Element
20909 * @param {Object} config The config object
20912 Roo.bootstrap.MessageBar = function(config){
20913 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20916 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20922 beforeClass: 'bootstrap-sticky-wrap',
20924 getAutoCreate : function(){
20928 cls: 'alert alert-dismissable alert-' + this.weight,
20933 html: this.html || ''
20939 cfg.cls += ' alert-messages-fixed';
20953 onRender : function(ct, position)
20955 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20958 var cfg = Roo.apply({}, this.getAutoCreate());
20962 cfg.cls += ' ' + this.cls;
20965 cfg.style = this.style;
20967 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20969 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20972 this.el.select('>button.close').on('click', this.hide, this);
20978 if (!this.rendered) {
20984 this.fireEvent('show', this);
20990 if (!this.rendered) {
20996 this.fireEvent('hide', this);
20999 update : function()
21001 // var e = this.el.dom.firstChild;
21003 // if(this.closable){
21004 // e = e.nextSibling;
21007 // e.data = this.html || '';
21009 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21025 * @class Roo.bootstrap.Graph
21026 * @extends Roo.bootstrap.Component
21027 * Bootstrap Graph class
21031 @cfg {String} graphtype bar | vbar | pie
21032 @cfg {number} g_x coodinator | centre x (pie)
21033 @cfg {number} g_y coodinator | centre y (pie)
21034 @cfg {number} g_r radius (pie)
21035 @cfg {number} g_height height of the chart (respected by all elements in the set)
21036 @cfg {number} g_width width of the chart (respected by all elements in the set)
21037 @cfg {Object} title The title of the chart
21040 -opts (object) options for the chart
21042 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21043 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21045 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.
21046 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21048 o stretch (boolean)
21050 -opts (object) options for the pie
21053 o startAngle (number)
21054 o endAngle (number)
21058 * Create a new Input
21059 * @param {Object} config The config object
21062 Roo.bootstrap.Graph = function(config){
21063 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21069 * The img click event for the img.
21070 * @param {Roo.EventObject} e
21076 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21087 //g_colors: this.colors,
21094 getAutoCreate : function(){
21105 onRender : function(ct,position){
21106 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21107 this.raphael = Raphael(this.el.dom);
21109 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21110 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21111 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21112 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21114 r.text(160, 10, "Single Series Chart").attr(txtattr);
21115 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21116 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21117 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21119 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21120 r.barchart(330, 10, 300, 220, data1);
21121 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21122 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21125 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21126 // r.barchart(30, 30, 560, 250, xdata, {
21127 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21128 // axis : "0 0 1 1",
21129 // axisxlabels : xdata
21130 // //yvalues : cols,
21133 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21135 // this.load(null,xdata,{
21136 // axis : "0 0 1 1",
21137 // axisxlabels : xdata
21142 load : function(graphtype,xdata,opts){
21143 this.raphael.clear();
21145 graphtype = this.graphtype;
21150 var r = this.raphael,
21151 fin = function () {
21152 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21154 fout = function () {
21155 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21157 pfin = function() {
21158 this.sector.stop();
21159 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21162 this.label[0].stop();
21163 this.label[0].attr({ r: 7.5 });
21164 this.label[1].attr({ "font-weight": 800 });
21167 pfout = function() {
21168 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21171 this.label[0].animate({ r: 5 }, 500, "bounce");
21172 this.label[1].attr({ "font-weight": 400 });
21178 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21181 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21184 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21185 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21187 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21194 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21199 setTitle: function(o)
21204 initEvents: function() {
21207 this.el.on('click', this.onClick, this);
21211 onClick : function(e)
21213 Roo.log('img onclick');
21214 this.fireEvent('click', this, e);
21226 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21229 * @class Roo.bootstrap.dash.NumberBox
21230 * @extends Roo.bootstrap.Component
21231 * Bootstrap NumberBox class
21232 * @cfg {String} headline Box headline
21233 * @cfg {String} content Box content
21234 * @cfg {String} icon Box icon
21235 * @cfg {String} footer Footer text
21236 * @cfg {String} fhref Footer href
21239 * Create a new NumberBox
21240 * @param {Object} config The config object
21244 Roo.bootstrap.dash.NumberBox = function(config){
21245 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21249 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21258 getAutoCreate : function(){
21262 cls : 'small-box ',
21270 cls : 'roo-headline',
21271 html : this.headline
21275 cls : 'roo-content',
21276 html : this.content
21290 cls : 'ion ' + this.icon
21299 cls : 'small-box-footer',
21300 href : this.fhref || '#',
21304 cfg.cn.push(footer);
21311 onRender : function(ct,position){
21312 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21319 setHeadline: function (value)
21321 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21324 setFooter: function (value, href)
21326 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21329 this.el.select('a.small-box-footer',true).first().attr('href', href);
21334 setContent: function (value)
21336 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21339 initEvents: function()
21353 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21356 * @class Roo.bootstrap.dash.TabBox
21357 * @extends Roo.bootstrap.Component
21358 * Bootstrap TabBox class
21359 * @cfg {String} title Title of the TabBox
21360 * @cfg {String} icon Icon of the TabBox
21361 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21362 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21365 * Create a new TabBox
21366 * @param {Object} config The config object
21370 Roo.bootstrap.dash.TabBox = function(config){
21371 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21376 * When a pane is added
21377 * @param {Roo.bootstrap.dash.TabPane} pane
21381 * @event activatepane
21382 * When a pane is activated
21383 * @param {Roo.bootstrap.dash.TabPane} pane
21385 "activatepane" : true
21393 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21398 tabScrollable : false,
21400 getChildContainer : function()
21402 return this.el.select('.tab-content', true).first();
21405 getAutoCreate : function(){
21409 cls: 'pull-left header',
21417 cls: 'fa ' + this.icon
21423 cls: 'nav nav-tabs pull-right',
21429 if(this.tabScrollable){
21436 cls: 'nav nav-tabs pull-right',
21447 cls: 'nav-tabs-custom',
21452 cls: 'tab-content no-padding',
21460 initEvents : function()
21462 //Roo.log('add add pane handler');
21463 this.on('addpane', this.onAddPane, this);
21466 * Updates the box title
21467 * @param {String} html to set the title to.
21469 setTitle : function(value)
21471 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21473 onAddPane : function(pane)
21475 this.panes.push(pane);
21476 //Roo.log('addpane');
21478 // tabs are rendere left to right..
21479 if(!this.showtabs){
21483 var ctr = this.el.select('.nav-tabs', true).first();
21486 var existing = ctr.select('.nav-tab',true);
21487 var qty = existing.getCount();;
21490 var tab = ctr.createChild({
21492 cls : 'nav-tab' + (qty ? '' : ' active'),
21500 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21503 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21505 pane.el.addClass('active');
21510 onTabClick : function(ev,un,ob,pane)
21512 //Roo.log('tab - prev default');
21513 ev.preventDefault();
21516 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21517 pane.tab.addClass('active');
21518 //Roo.log(pane.title);
21519 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21520 // technically we should have a deactivate event.. but maybe add later.
21521 // and it should not de-activate the selected tab...
21522 this.fireEvent('activatepane', pane);
21523 pane.el.addClass('active');
21524 pane.fireEvent('activate');
21529 getActivePane : function()
21532 Roo.each(this.panes, function(p) {
21533 if(p.el.hasClass('active')){
21554 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21556 * @class Roo.bootstrap.TabPane
21557 * @extends Roo.bootstrap.Component
21558 * Bootstrap TabPane class
21559 * @cfg {Boolean} active (false | true) Default false
21560 * @cfg {String} title title of panel
21564 * Create a new TabPane
21565 * @param {Object} config The config object
21568 Roo.bootstrap.dash.TabPane = function(config){
21569 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21575 * When a pane is activated
21576 * @param {Roo.bootstrap.dash.TabPane} pane
21583 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21588 // the tabBox that this is attached to.
21591 getAutoCreate : function()
21599 cfg.cls += ' active';
21604 initEvents : function()
21606 //Roo.log('trigger add pane handler');
21607 this.parent().fireEvent('addpane', this)
21611 * Updates the tab title
21612 * @param {String} html to set the title to.
21614 setTitle: function(str)
21620 this.tab.select('a', true).first().dom.innerHTML = str;
21637 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21640 * @class Roo.bootstrap.menu.Menu
21641 * @extends Roo.bootstrap.Component
21642 * Bootstrap Menu class - container for Menu
21643 * @cfg {String} html Text of the menu
21644 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21645 * @cfg {String} icon Font awesome icon
21646 * @cfg {String} pos Menu align to (top | bottom) default bottom
21650 * Create a new Menu
21651 * @param {Object} config The config object
21655 Roo.bootstrap.menu.Menu = function(config){
21656 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21660 * @event beforeshow
21661 * Fires before this menu is displayed
21662 * @param {Roo.bootstrap.menu.Menu} this
21666 * @event beforehide
21667 * Fires before this menu is hidden
21668 * @param {Roo.bootstrap.menu.Menu} this
21673 * Fires after this menu is displayed
21674 * @param {Roo.bootstrap.menu.Menu} this
21679 * Fires after this menu is hidden
21680 * @param {Roo.bootstrap.menu.Menu} this
21685 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21686 * @param {Roo.bootstrap.menu.Menu} this
21687 * @param {Roo.EventObject} e
21694 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21698 weight : 'default',
21703 getChildContainer : function() {
21704 if(this.isSubMenu){
21708 return this.el.select('ul.dropdown-menu', true).first();
21711 getAutoCreate : function()
21716 cls : 'roo-menu-text',
21724 cls : 'fa ' + this.icon
21735 cls : 'dropdown-button btn btn-' + this.weight,
21740 cls : 'dropdown-toggle btn btn-' + this.weight,
21750 cls : 'dropdown-menu'
21756 if(this.pos == 'top'){
21757 cfg.cls += ' dropup';
21760 if(this.isSubMenu){
21763 cls : 'dropdown-menu'
21770 onRender : function(ct, position)
21772 this.isSubMenu = ct.hasClass('dropdown-submenu');
21774 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21777 initEvents : function()
21779 if(this.isSubMenu){
21783 this.hidden = true;
21785 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21786 this.triggerEl.on('click', this.onTriggerPress, this);
21788 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21789 this.buttonEl.on('click', this.onClick, this);
21795 if(this.isSubMenu){
21799 return this.el.select('ul.dropdown-menu', true).first();
21802 onClick : function(e)
21804 this.fireEvent("click", this, e);
21807 onTriggerPress : function(e)
21809 if (this.isVisible()) {
21816 isVisible : function(){
21817 return !this.hidden;
21822 this.fireEvent("beforeshow", this);
21824 this.hidden = false;
21825 this.el.addClass('open');
21827 Roo.get(document).on("mouseup", this.onMouseUp, this);
21829 this.fireEvent("show", this);
21836 this.fireEvent("beforehide", this);
21838 this.hidden = true;
21839 this.el.removeClass('open');
21841 Roo.get(document).un("mouseup", this.onMouseUp);
21843 this.fireEvent("hide", this);
21846 onMouseUp : function()
21860 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21863 * @class Roo.bootstrap.menu.Item
21864 * @extends Roo.bootstrap.Component
21865 * Bootstrap MenuItem class
21866 * @cfg {Boolean} submenu (true | false) default false
21867 * @cfg {String} html text of the item
21868 * @cfg {String} href the link
21869 * @cfg {Boolean} disable (true | false) default false
21870 * @cfg {Boolean} preventDefault (true | false) default true
21871 * @cfg {String} icon Font awesome icon
21872 * @cfg {String} pos Submenu align to (left | right) default right
21876 * Create a new Item
21877 * @param {Object} config The config object
21881 Roo.bootstrap.menu.Item = function(config){
21882 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21886 * Fires when the mouse is hovering over this menu
21887 * @param {Roo.bootstrap.menu.Item} this
21888 * @param {Roo.EventObject} e
21893 * Fires when the mouse exits this menu
21894 * @param {Roo.bootstrap.menu.Item} this
21895 * @param {Roo.EventObject} e
21901 * The raw click event for the entire grid.
21902 * @param {Roo.EventObject} e
21908 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21913 preventDefault: true,
21918 getAutoCreate : function()
21923 cls : 'roo-menu-item-text',
21931 cls : 'fa ' + this.icon
21940 href : this.href || '#',
21947 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21951 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21953 if(this.pos == 'left'){
21954 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21961 initEvents : function()
21963 this.el.on('mouseover', this.onMouseOver, this);
21964 this.el.on('mouseout', this.onMouseOut, this);
21966 this.el.select('a', true).first().on('click', this.onClick, this);
21970 onClick : function(e)
21972 if(this.preventDefault){
21973 e.preventDefault();
21976 this.fireEvent("click", this, e);
21979 onMouseOver : function(e)
21981 if(this.submenu && this.pos == 'left'){
21982 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21985 this.fireEvent("mouseover", this, e);
21988 onMouseOut : function(e)
21990 this.fireEvent("mouseout", this, e);
22002 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22005 * @class Roo.bootstrap.menu.Separator
22006 * @extends Roo.bootstrap.Component
22007 * Bootstrap Separator class
22010 * Create a new Separator
22011 * @param {Object} config The config object
22015 Roo.bootstrap.menu.Separator = function(config){
22016 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22019 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22021 getAutoCreate : function(){
22042 * @class Roo.bootstrap.Tooltip
22043 * Bootstrap Tooltip class
22044 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22045 * to determine which dom element triggers the tooltip.
22047 * It needs to add support for additional attributes like tooltip-position
22050 * Create a new Toolti
22051 * @param {Object} config The config object
22054 Roo.bootstrap.Tooltip = function(config){
22055 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22058 Roo.apply(Roo.bootstrap.Tooltip, {
22060 * @function init initialize tooltip monitoring.
22064 currentTip : false,
22065 currentRegion : false,
22071 Roo.get(document).on('mouseover', this.enter ,this);
22072 Roo.get(document).on('mouseout', this.leave, this);
22075 this.currentTip = new Roo.bootstrap.Tooltip();
22078 enter : function(ev)
22080 var dom = ev.getTarget();
22082 //Roo.log(['enter',dom]);
22083 var el = Roo.fly(dom);
22084 if (this.currentEl) {
22086 //Roo.log(this.currentEl);
22087 //Roo.log(this.currentEl.contains(dom));
22088 if (this.currentEl == el) {
22091 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22099 if (this.currentTip.el) {
22100 this.currentTip.el.hide(); // force hiding...
22105 // you can not look for children, as if el is the body.. then everythign is the child..
22106 if (!el.attr('tooltip')) { //
22107 if (!el.select("[tooltip]").elements.length) {
22110 // is the mouse over this child...?
22111 bindEl = el.select("[tooltip]").first();
22112 var xy = ev.getXY();
22113 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22114 //Roo.log("not in region.");
22117 //Roo.log("child element over..");
22120 this.currentEl = bindEl;
22121 this.currentTip.bind(bindEl);
22122 this.currentRegion = Roo.lib.Region.getRegion(dom);
22123 this.currentTip.enter();
22126 leave : function(ev)
22128 var dom = ev.getTarget();
22129 //Roo.log(['leave',dom]);
22130 if (!this.currentEl) {
22135 if (dom != this.currentEl.dom) {
22138 var xy = ev.getXY();
22139 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22142 // only activate leave if mouse cursor is outside... bounding box..
22147 if (this.currentTip) {
22148 this.currentTip.leave();
22150 //Roo.log('clear currentEl');
22151 this.currentEl = false;
22156 'left' : ['r-l', [-2,0], 'right'],
22157 'right' : ['l-r', [2,0], 'left'],
22158 'bottom' : ['t-b', [0,2], 'top'],
22159 'top' : [ 'b-t', [0,-2], 'bottom']
22165 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22170 delay : null, // can be { show : 300 , hide: 500}
22174 hoverState : null, //???
22176 placement : 'bottom',
22178 getAutoCreate : function(){
22185 cls : 'tooltip-arrow'
22188 cls : 'tooltip-inner'
22195 bind : function(el)
22201 enter : function () {
22203 if (this.timeout != null) {
22204 clearTimeout(this.timeout);
22207 this.hoverState = 'in';
22208 //Roo.log("enter - show");
22209 if (!this.delay || !this.delay.show) {
22214 this.timeout = setTimeout(function () {
22215 if (_t.hoverState == 'in') {
22218 }, this.delay.show);
22222 clearTimeout(this.timeout);
22224 this.hoverState = 'out';
22225 if (!this.delay || !this.delay.hide) {
22231 this.timeout = setTimeout(function () {
22232 //Roo.log("leave - timeout");
22234 if (_t.hoverState == 'out') {
22236 Roo.bootstrap.Tooltip.currentEl = false;
22244 this.render(document.body);
22247 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22249 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22251 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22253 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22255 var placement = typeof this.placement == 'function' ?
22256 this.placement.call(this, this.el, on_el) :
22259 var autoToken = /\s?auto?\s?/i;
22260 var autoPlace = autoToken.test(placement);
22262 placement = placement.replace(autoToken, '') || 'top';
22266 //this.el.setXY([0,0]);
22268 //this.el.dom.style.display='block';
22269 this.el.addClass(placement);
22271 //this.el.appendTo(on_el);
22273 var p = this.getPosition();
22274 var box = this.el.getBox();
22279 var align = Roo.bootstrap.Tooltip.alignment[placement];
22280 this.el.alignTo(this.bindEl, align[0],align[1]);
22281 //var arrow = this.el.select('.arrow',true).first();
22282 //arrow.set(align[2],
22284 this.el.addClass('in fade');
22285 this.hoverState = null;
22287 if (this.el.hasClass('fade')) {
22298 //this.el.setXY([0,0]);
22299 this.el.removeClass('in');
22315 * @class Roo.bootstrap.LocationPicker
22316 * @extends Roo.bootstrap.Component
22317 * Bootstrap LocationPicker class
22318 * @cfg {Number} latitude Position when init default 0
22319 * @cfg {Number} longitude Position when init default 0
22320 * @cfg {Number} zoom default 15
22321 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22322 * @cfg {Boolean} mapTypeControl default false
22323 * @cfg {Boolean} disableDoubleClickZoom default false
22324 * @cfg {Boolean} scrollwheel default true
22325 * @cfg {Boolean} streetViewControl default false
22326 * @cfg {Number} radius default 0
22327 * @cfg {String} locationName
22328 * @cfg {Boolean} draggable default true
22329 * @cfg {Boolean} enableAutocomplete default false
22330 * @cfg {Boolean} enableReverseGeocode default true
22331 * @cfg {String} markerTitle
22334 * Create a new LocationPicker
22335 * @param {Object} config The config object
22339 Roo.bootstrap.LocationPicker = function(config){
22341 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22346 * Fires when the picker initialized.
22347 * @param {Roo.bootstrap.LocationPicker} this
22348 * @param {Google Location} location
22352 * @event positionchanged
22353 * Fires when the picker position changed.
22354 * @param {Roo.bootstrap.LocationPicker} this
22355 * @param {Google Location} location
22357 positionchanged : true,
22360 * Fires when the map resize.
22361 * @param {Roo.bootstrap.LocationPicker} this
22366 * Fires when the map show.
22367 * @param {Roo.bootstrap.LocationPicker} this
22372 * Fires when the map hide.
22373 * @param {Roo.bootstrap.LocationPicker} this
22378 * Fires when click the map.
22379 * @param {Roo.bootstrap.LocationPicker} this
22380 * @param {Map event} e
22384 * @event mapRightClick
22385 * Fires when right click the map.
22386 * @param {Roo.bootstrap.LocationPicker} this
22387 * @param {Map event} e
22389 mapRightClick : true,
22391 * @event markerClick
22392 * Fires when click the marker.
22393 * @param {Roo.bootstrap.LocationPicker} this
22394 * @param {Map event} e
22396 markerClick : true,
22398 * @event markerRightClick
22399 * Fires when right click the marker.
22400 * @param {Roo.bootstrap.LocationPicker} this
22401 * @param {Map event} e
22403 markerRightClick : true,
22405 * @event OverlayViewDraw
22406 * Fires when OverlayView Draw
22407 * @param {Roo.bootstrap.LocationPicker} this
22409 OverlayViewDraw : true,
22411 * @event OverlayViewOnAdd
22412 * Fires when OverlayView Draw
22413 * @param {Roo.bootstrap.LocationPicker} this
22415 OverlayViewOnAdd : true,
22417 * @event OverlayViewOnRemove
22418 * Fires when OverlayView Draw
22419 * @param {Roo.bootstrap.LocationPicker} this
22421 OverlayViewOnRemove : true,
22423 * @event OverlayViewShow
22424 * Fires when OverlayView Draw
22425 * @param {Roo.bootstrap.LocationPicker} this
22426 * @param {Pixel} cpx
22428 OverlayViewShow : true,
22430 * @event OverlayViewHide
22431 * Fires when OverlayView Draw
22432 * @param {Roo.bootstrap.LocationPicker} this
22434 OverlayViewHide : true
22439 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22441 gMapContext: false,
22447 mapTypeControl: false,
22448 disableDoubleClickZoom: false,
22450 streetViewControl: false,
22454 enableAutocomplete: false,
22455 enableReverseGeocode: true,
22458 getAutoCreate: function()
22463 cls: 'roo-location-picker'
22469 initEvents: function(ct, position)
22471 if(!this.el.getWidth() || this.isApplied()){
22475 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22480 initial: function()
22482 if(!this.mapTypeId){
22483 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22486 this.gMapContext = this.GMapContext();
22488 this.initOverlayView();
22490 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22494 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22495 _this.setPosition(_this.gMapContext.marker.position);
22498 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22499 _this.fireEvent('mapClick', this, event);
22503 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22504 _this.fireEvent('mapRightClick', this, event);
22508 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22509 _this.fireEvent('markerClick', this, event);
22513 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22514 _this.fireEvent('markerRightClick', this, event);
22518 this.setPosition(this.gMapContext.location);
22520 this.fireEvent('initial', this, this.gMapContext.location);
22523 initOverlayView: function()
22527 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22531 _this.fireEvent('OverlayViewDraw', _this);
22536 _this.fireEvent('OverlayViewOnAdd', _this);
22539 onRemove: function()
22541 _this.fireEvent('OverlayViewOnRemove', _this);
22544 show: function(cpx)
22546 _this.fireEvent('OverlayViewShow', _this, cpx);
22551 _this.fireEvent('OverlayViewHide', _this);
22557 fromLatLngToContainerPixel: function(event)
22559 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22562 isApplied: function()
22564 return this.getGmapContext() == false ? false : true;
22567 getGmapContext: function()
22569 return this.gMapContext
22572 GMapContext: function()
22574 var position = new google.maps.LatLng(this.latitude, this.longitude);
22576 var _map = new google.maps.Map(this.el.dom, {
22579 mapTypeId: this.mapTypeId,
22580 mapTypeControl: this.mapTypeControl,
22581 disableDoubleClickZoom: this.disableDoubleClickZoom,
22582 scrollwheel: this.scrollwheel,
22583 streetViewControl: this.streetViewControl,
22584 locationName: this.locationName,
22585 draggable: this.draggable,
22586 enableAutocomplete: this.enableAutocomplete,
22587 enableReverseGeocode: this.enableReverseGeocode
22590 var _marker = new google.maps.Marker({
22591 position: position,
22593 title: this.markerTitle,
22594 draggable: this.draggable
22601 location: position,
22602 radius: this.radius,
22603 locationName: this.locationName,
22604 addressComponents: {
22605 formatted_address: null,
22606 addressLine1: null,
22607 addressLine2: null,
22609 streetNumber: null,
22613 stateOrProvince: null
22616 domContainer: this.el.dom,
22617 geodecoder: new google.maps.Geocoder()
22621 drawCircle: function(center, radius, options)
22623 if (this.gMapContext.circle != null) {
22624 this.gMapContext.circle.setMap(null);
22628 options = Roo.apply({}, options, {
22629 strokeColor: "#0000FF",
22630 strokeOpacity: .35,
22632 fillColor: "#0000FF",
22636 options.map = this.gMapContext.map;
22637 options.radius = radius;
22638 options.center = center;
22639 this.gMapContext.circle = new google.maps.Circle(options);
22640 return this.gMapContext.circle;
22646 setPosition: function(location)
22648 this.gMapContext.location = location;
22649 this.gMapContext.marker.setPosition(location);
22650 this.gMapContext.map.panTo(location);
22651 this.drawCircle(location, this.gMapContext.radius, {});
22655 if (this.gMapContext.settings.enableReverseGeocode) {
22656 this.gMapContext.geodecoder.geocode({
22657 latLng: this.gMapContext.location
22658 }, function(results, status) {
22660 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22661 _this.gMapContext.locationName = results[0].formatted_address;
22662 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22664 _this.fireEvent('positionchanged', this, location);
22671 this.fireEvent('positionchanged', this, location);
22676 google.maps.event.trigger(this.gMapContext.map, "resize");
22678 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22680 this.fireEvent('resize', this);
22683 setPositionByLatLng: function(latitude, longitude)
22685 this.setPosition(new google.maps.LatLng(latitude, longitude));
22688 getCurrentPosition: function()
22691 latitude: this.gMapContext.location.lat(),
22692 longitude: this.gMapContext.location.lng()
22696 getAddressName: function()
22698 return this.gMapContext.locationName;
22701 getAddressComponents: function()
22703 return this.gMapContext.addressComponents;
22706 address_component_from_google_geocode: function(address_components)
22710 for (var i = 0; i < address_components.length; i++) {
22711 var component = address_components[i];
22712 if (component.types.indexOf("postal_code") >= 0) {
22713 result.postalCode = component.short_name;
22714 } else if (component.types.indexOf("street_number") >= 0) {
22715 result.streetNumber = component.short_name;
22716 } else if (component.types.indexOf("route") >= 0) {
22717 result.streetName = component.short_name;
22718 } else if (component.types.indexOf("neighborhood") >= 0) {
22719 result.city = component.short_name;
22720 } else if (component.types.indexOf("locality") >= 0) {
22721 result.city = component.short_name;
22722 } else if (component.types.indexOf("sublocality") >= 0) {
22723 result.district = component.short_name;
22724 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22725 result.stateOrProvince = component.short_name;
22726 } else if (component.types.indexOf("country") >= 0) {
22727 result.country = component.short_name;
22731 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22732 result.addressLine2 = "";
22736 setZoomLevel: function(zoom)
22738 this.gMapContext.map.setZoom(zoom);
22751 this.fireEvent('show', this);
22762 this.fireEvent('hide', this);
22767 Roo.apply(Roo.bootstrap.LocationPicker, {
22769 OverlayView : function(map, options)
22771 options = options || {};
22785 * @class Roo.bootstrap.Alert
22786 * @extends Roo.bootstrap.Component
22787 * Bootstrap Alert class
22788 * @cfg {String} title The title of alert
22789 * @cfg {String} html The content of alert
22790 * @cfg {String} weight ( success | info | warning | danger )
22791 * @cfg {String} faicon font-awesomeicon
22794 * Create a new alert
22795 * @param {Object} config The config object
22799 Roo.bootstrap.Alert = function(config){
22800 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22804 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22811 getAutoCreate : function()
22820 cls : 'roo-alert-icon'
22825 cls : 'roo-alert-title',
22830 cls : 'roo-alert-text',
22837 cfg.cn[0].cls += ' fa ' + this.faicon;
22841 cfg.cls += ' alert-' + this.weight;
22847 initEvents: function()
22849 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22852 setTitle : function(str)
22854 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22857 setText : function(str)
22859 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22862 setWeight : function(weight)
22865 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22868 this.weight = weight;
22870 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22873 setIcon : function(icon)
22876 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22881 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);