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);
1845 //xy = this.el.adjustForConstraints(xy);
1849 this.hideMenuItems();
1850 this.hidden = false;
1851 this.triggerEl.addClass('open');
1853 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1854 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1859 this.fireEvent("show", this);
1865 this.doFocus.defer(50, this);
1869 doFocus : function(){
1871 this.focusEl.focus();
1876 * Hides this menu and optionally all parent menus
1877 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1879 hide : function(deep){
1881 this.hideMenuItems();
1882 if(this.el && this.isVisible()){
1883 this.fireEvent("beforehide", this);
1884 if(this.activeItem){
1885 this.activeItem.deactivate();
1886 this.activeItem = null;
1888 this.triggerEl.removeClass('open');;
1890 this.fireEvent("hide", this);
1892 if(deep === true && this.parentMenu){
1893 this.parentMenu.hide(true);
1897 onTriggerPress : function(e)
1900 Roo.log('trigger press');
1901 //Roo.log(e.getTarget());
1902 // Roo.log(this.triggerEl.dom);
1903 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1906 if (this.isVisible()) {
1910 this.show(this.triggerEl, false, false);
1919 hideMenuItems : function()
1921 //$(backdrop).remove()
1922 Roo.select('.open',true).each(function(aa) {
1924 aa.removeClass('open');
1925 //var parent = getParent($(this))
1926 //var relatedTarget = { relatedTarget: this }
1928 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1929 //if (e.isDefaultPrevented()) return
1930 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1933 addxtypeChild : function (tree, cntr) {
1934 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1936 this.menuitems.add(comp);
1957 * @class Roo.bootstrap.MenuItem
1958 * @extends Roo.bootstrap.Component
1959 * Bootstrap MenuItem class
1960 * @cfg {String} html the menu label
1961 * @cfg {String} href the link
1962 * @cfg {Boolean} preventDefault (true | false) default true
1963 * @cfg {Boolean} isContainer (true | false) default false
1967 * Create a new MenuItem
1968 * @param {Object} config The config object
1972 Roo.bootstrap.MenuItem = function(config){
1973 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1978 * The raw click event for the entire grid.
1979 * @param {Roo.bootstrap.MenuItem} this
1980 * @param {Roo.EventObject} e
1986 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1990 preventDefault: true,
1991 isContainer : false,
1993 getAutoCreate : function(){
1995 if(this.isContainer){
1998 cls: 'dropdown-menu-item'
2004 cls: 'dropdown-menu-item',
2013 if (this.parent().type == 'treeview') {
2014 cfg.cls = 'treeview-menu';
2017 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2018 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2022 initEvents: function() {
2024 //this.el.select('a').on('click', this.onClick, this);
2027 onClick : function(e)
2029 Roo.log('item on click ');
2030 //if(this.preventDefault){
2031 // e.preventDefault();
2033 //this.parent().hideMenuItems();
2035 this.fireEvent('click', this, e);
2054 * @class Roo.bootstrap.MenuSeparator
2055 * @extends Roo.bootstrap.Component
2056 * Bootstrap MenuSeparator class
2059 * Create a new MenuItem
2060 * @param {Object} config The config object
2064 Roo.bootstrap.MenuSeparator = function(config){
2065 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2068 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2070 getAutoCreate : function(){
2089 * @class Roo.bootstrap.Modal
2090 * @extends Roo.bootstrap.Component
2091 * Bootstrap Modal class
2092 * @cfg {String} title Title of dialog
2093 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2094 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2095 * @cfg {Boolean} specificTitle default false
2096 * @cfg {Array} buttons Array of buttons or standard button set..
2097 * @cfg {String} buttonPosition (left|right|center) default right
2098 * @cfg {Boolean} animate default true
2099 * @cfg {Boolean} allow_close default true
2102 * Create a new Modal Dialog
2103 * @param {Object} config The config object
2106 Roo.bootstrap.Modal = function(config){
2107 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2112 * The raw btnclick event for the button
2113 * @param {Roo.EventObject} e
2117 this.buttons = this.buttons || [];
2120 this.tmpl = Roo.factory(this.tmpl);
2125 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2127 title : 'test dialog',
2137 specificTitle: false,
2139 buttonPosition: 'right',
2153 onRender : function(ct, position)
2155 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2158 var cfg = Roo.apply({}, this.getAutoCreate());
2161 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2163 //if (!cfg.name.length) {
2167 cfg.cls += ' ' + this.cls;
2170 cfg.style = this.style;
2172 this.el = Roo.get(document.body).createChild(cfg, position);
2174 //var type = this.el.dom.type;
2179 if(this.tabIndex !== undefined){
2180 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2184 this.bodyEl = this.el.select('.modal-body',true).first();
2185 this.closeEl = this.el.select('.modal-header .close', true).first();
2186 this.footerEl = this.el.select('.modal-footer',true).first();
2187 this.titleEl = this.el.select('.modal-title',true).first();
2191 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2192 this.maskEl.enableDisplayMode("block");
2194 //this.el.addClass("x-dlg-modal");
2196 if (this.buttons.length) {
2197 Roo.each(this.buttons, function(bb) {
2198 b = Roo.apply({}, bb);
2199 b.xns = b.xns || Roo.bootstrap;
2200 b.xtype = b.xtype || 'Button';
2201 if (typeof(b.listeners) == 'undefined') {
2202 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2205 var btn = Roo.factory(b);
2207 btn.onRender(this.el.select('.modal-footer div').first());
2211 // render the children.
2214 if(typeof(this.items) != 'undefined'){
2215 var items = this.items;
2218 for(var i =0;i < items.length;i++) {
2219 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2223 this.items = nitems;
2225 // where are these used - they used to be body/close/footer
2229 //this.el.addClass([this.fieldClass, this.cls]);
2232 getAutoCreate : function(){
2237 html : this.html || ''
2242 cls : 'modal-title',
2246 if(this.specificTitle){
2252 if (this.allow_close) {
2263 style : 'display: none',
2266 cls: "modal-dialog",
2269 cls : "modal-content",
2272 cls : 'modal-header',
2277 cls : 'modal-footer',
2281 cls: 'btn-' + this.buttonPosition
2298 modal.cls += ' fade';
2304 getChildContainer : function() {
2309 getButtonContainer : function() {
2310 return this.el.select('.modal-footer div',true).first();
2313 initEvents : function()
2315 if (this.allow_close) {
2316 this.closeEl.on('click', this.hide, this);
2322 if (!this.rendered) {
2326 this.el.setStyle('display', 'block');
2330 (function(){ _this.el.addClass('in'); }).defer(50);
2332 this.el.addClass('in');
2335 // not sure how we can show data in here..
2337 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2340 Roo.get(document.body).addClass("x-body-masked");
2341 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2343 this.el.setStyle('zIndex', '10001');
2345 this.fireEvent('show', this);
2352 Roo.get(document.body).removeClass("x-body-masked");
2353 this.el.removeClass('in');
2357 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2359 this.el.setStyle('display', 'none');
2362 this.fireEvent('hide', this);
2365 addButton : function(str, cb)
2369 var b = Roo.apply({}, { html : str } );
2370 b.xns = b.xns || Roo.bootstrap;
2371 b.xtype = b.xtype || 'Button';
2372 if (typeof(b.listeners) == 'undefined') {
2373 b.listeners = { click : cb.createDelegate(this) };
2376 var btn = Roo.factory(b);
2378 btn.onRender(this.el.select('.modal-footer div').first());
2384 setDefaultButton : function(btn)
2386 //this.el.select('.modal-footer').()
2388 resizeTo: function(w,h)
2392 setContentSize : function(w, h)
2396 onButtonClick: function(btn,e)
2399 this.fireEvent('btnclick', btn.name, e);
2402 * Set the title of the Dialog
2403 * @param {String} str new Title
2405 setTitle: function(str) {
2406 this.titleEl.dom.innerHTML = str;
2409 * Set the body of the Dialog
2410 * @param {String} str new Title
2412 setBody: function(str) {
2413 this.bodyEl.dom.innerHTML = str;
2416 * Set the body of the Dialog using the template
2417 * @param {Obj} data - apply this data to the template and replace the body contents.
2419 applyBody: function(obj)
2422 Roo.log("Error - using apply Body without a template");
2425 this.tmpl.overwrite(this.bodyEl, obj);
2431 Roo.apply(Roo.bootstrap.Modal, {
2433 * Button config that displays a single OK button
2442 * Button config that displays Yes and No buttons
2458 * Button config that displays OK and Cancel buttons
2473 * Button config that displays Yes, No and Cancel buttons
2496 * messagebox - can be used as a replace
2500 * @class Roo.MessageBox
2501 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2505 Roo.Msg.alert('Status', 'Changes saved successfully.');
2507 // Prompt for user data:
2508 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2510 // process text value...
2514 // Show a dialog using config options:
2516 title:'Save Changes?',
2517 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2518 buttons: Roo.Msg.YESNOCANCEL,
2525 Roo.bootstrap.MessageBox = function(){
2526 var dlg, opt, mask, waitTimer;
2527 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2528 var buttons, activeTextEl, bwidth;
2532 var handleButton = function(button){
2534 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2538 var handleHide = function(){
2540 dlg.el.removeClass(opt.cls);
2543 // Roo.TaskMgr.stop(waitTimer);
2544 // waitTimer = null;
2549 var updateButtons = function(b){
2552 buttons["ok"].hide();
2553 buttons["cancel"].hide();
2554 buttons["yes"].hide();
2555 buttons["no"].hide();
2556 //dlg.footer.dom.style.display = 'none';
2559 dlg.footerEl.dom.style.display = '';
2560 for(var k in buttons){
2561 if(typeof buttons[k] != "function"){
2564 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2565 width += buttons[k].el.getWidth()+15;
2575 var handleEsc = function(d, k, e){
2576 if(opt && opt.closable !== false){
2586 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2587 * @return {Roo.BasicDialog} The BasicDialog element
2589 getDialog : function(){
2591 dlg = new Roo.bootstrap.Modal( {
2594 //constraintoviewport:false,
2596 //collapsible : false,
2601 //buttonAlign:"center",
2602 closeClick : function(){
2603 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2606 handleButton("cancel");
2611 dlg.on("hide", handleHide);
2613 //dlg.addKeyListener(27, handleEsc);
2615 this.buttons = buttons;
2616 var bt = this.buttonText;
2617 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2618 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2619 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2620 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2622 bodyEl = dlg.bodyEl.createChild({
2624 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2625 '<textarea class="roo-mb-textarea"></textarea>' +
2626 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2628 msgEl = bodyEl.dom.firstChild;
2629 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2630 textboxEl.enableDisplayMode();
2631 textboxEl.addKeyListener([10,13], function(){
2632 if(dlg.isVisible() && opt && opt.buttons){
2635 }else if(opt.buttons.yes){
2636 handleButton("yes");
2640 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2641 textareaEl.enableDisplayMode();
2642 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2643 progressEl.enableDisplayMode();
2644 var pf = progressEl.dom.firstChild;
2646 pp = Roo.get(pf.firstChild);
2647 pp.setHeight(pf.offsetHeight);
2655 * Updates the message box body text
2656 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2657 * the XHTML-compliant non-breaking space character '&#160;')
2658 * @return {Roo.MessageBox} This message box
2660 updateText : function(text){
2661 if(!dlg.isVisible() && !opt.width){
2662 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2664 msgEl.innerHTML = text || ' ';
2666 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2667 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2669 Math.min(opt.width || cw , this.maxWidth),
2670 Math.max(opt.minWidth || this.minWidth, bwidth)
2673 activeTextEl.setWidth(w);
2675 if(dlg.isVisible()){
2676 dlg.fixedcenter = false;
2678 // to big, make it scroll. = But as usual stupid IE does not support
2681 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2682 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2683 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2685 bodyEl.dom.style.height = '';
2686 bodyEl.dom.style.overflowY = '';
2689 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2691 bodyEl.dom.style.overflowX = '';
2694 dlg.setContentSize(w, bodyEl.getHeight());
2695 if(dlg.isVisible()){
2696 dlg.fixedcenter = true;
2702 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2703 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2704 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2705 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2706 * @return {Roo.MessageBox} This message box
2708 updateProgress : function(value, text){
2710 this.updateText(text);
2712 if (pp) { // weird bug on my firefox - for some reason this is not defined
2713 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2719 * Returns true if the message box is currently displayed
2720 * @return {Boolean} True if the message box is visible, else false
2722 isVisible : function(){
2723 return dlg && dlg.isVisible();
2727 * Hides the message box if it is displayed
2730 if(this.isVisible()){
2736 * Displays a new message box, or reinitializes an existing message box, based on the config options
2737 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2738 * The following config object properties are supported:
2740 Property Type Description
2741 ---------- --------------- ------------------------------------------------------------------------------------
2742 animEl String/Element An id or Element from which the message box should animate as it opens and
2743 closes (defaults to undefined)
2744 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2745 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2746 closable Boolean False to hide the top-right close button (defaults to true). Note that
2747 progress and wait dialogs will ignore this property and always hide the
2748 close button as they can only be closed programmatically.
2749 cls String A custom CSS class to apply to the message box element
2750 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2751 displayed (defaults to 75)
2752 fn Function A callback function to execute after closing the dialog. The arguments to the
2753 function will be btn (the name of the button that was clicked, if applicable,
2754 e.g. "ok"), and text (the value of the active text field, if applicable).
2755 Progress and wait dialogs will ignore this option since they do not respond to
2756 user actions and can only be closed programmatically, so any required function
2757 should be called by the same code after it closes the dialog.
2758 icon String A CSS class that provides a background image to be used as an icon for
2759 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2760 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2761 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2762 modal Boolean False to allow user interaction with the page while the message box is
2763 displayed (defaults to true)
2764 msg String A string that will replace the existing message box body text (defaults
2765 to the XHTML-compliant non-breaking space character ' ')
2766 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2767 progress Boolean True to display a progress bar (defaults to false)
2768 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2769 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2770 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2771 title String The title text
2772 value String The string value to set into the active textbox element if displayed
2773 wait Boolean True to display a progress bar (defaults to false)
2774 width Number The width of the dialog in pixels
2781 msg: 'Please enter your address:',
2783 buttons: Roo.MessageBox.OKCANCEL,
2786 animEl: 'addAddressBtn'
2789 * @param {Object} config Configuration options
2790 * @return {Roo.MessageBox} This message box
2792 show : function(options)
2795 // this causes nightmares if you show one dialog after another
2796 // especially on callbacks..
2798 if(this.isVisible()){
2801 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2802 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2803 Roo.log("New Dialog Message:" + options.msg )
2804 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2805 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2808 var d = this.getDialog();
2810 d.setTitle(opt.title || " ");
2811 d.closeEl.setDisplayed(opt.closable !== false);
2812 activeTextEl = textboxEl;
2813 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2818 textareaEl.setHeight(typeof opt.multiline == "number" ?
2819 opt.multiline : this.defaultTextHeight);
2820 activeTextEl = textareaEl;
2829 progressEl.setDisplayed(opt.progress === true);
2830 this.updateProgress(0);
2831 activeTextEl.dom.value = opt.value || "";
2833 dlg.setDefaultButton(activeTextEl);
2835 var bs = opt.buttons;
2839 }else if(bs && bs.yes){
2840 db = buttons["yes"];
2842 dlg.setDefaultButton(db);
2844 bwidth = updateButtons(opt.buttons);
2845 this.updateText(opt.msg);
2847 d.el.addClass(opt.cls);
2849 d.proxyDrag = opt.proxyDrag === true;
2850 d.modal = opt.modal !== false;
2851 d.mask = opt.modal !== false ? mask : false;
2853 // force it to the end of the z-index stack so it gets a cursor in FF
2854 document.body.appendChild(dlg.el.dom);
2855 d.animateTarget = null;
2856 d.show(options.animEl);
2862 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2863 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2864 * and closing the message box when the process is complete.
2865 * @param {String} title The title bar text
2866 * @param {String} msg The message box body text
2867 * @return {Roo.MessageBox} This message box
2869 progress : function(title, msg){
2876 minWidth: this.minProgressWidth,
2883 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2884 * If a callback function is passed it will be called after the user clicks the button, and the
2885 * id of the button that was clicked will be passed as the only parameter to the callback
2886 * (could also be the top-right close button).
2887 * @param {String} title The title bar text
2888 * @param {String} msg The message box body text
2889 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2890 * @param {Object} scope (optional) The scope of the callback function
2891 * @return {Roo.MessageBox} This message box
2893 alert : function(title, msg, fn, scope){
2906 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2907 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2908 * You are responsible for closing the message box when the process is complete.
2909 * @param {String} msg The message box body text
2910 * @param {String} title (optional) The title bar text
2911 * @return {Roo.MessageBox} This message box
2913 wait : function(msg, title){
2924 waitTimer = Roo.TaskMgr.start({
2926 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2934 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2935 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2936 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2937 * @param {String} title The title bar text
2938 * @param {String} msg The message box body text
2939 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2940 * @param {Object} scope (optional) The scope of the callback function
2941 * @return {Roo.MessageBox} This message box
2943 confirm : function(title, msg, fn, scope){
2947 buttons: this.YESNO,
2956 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2957 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2958 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2959 * (could also be the top-right close button) and the text that was entered will be passed as the two
2960 * parameters to the callback.
2961 * @param {String} title The title bar text
2962 * @param {String} msg The message box body text
2963 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2964 * @param {Object} scope (optional) The scope of the callback function
2965 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2966 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2967 * @return {Roo.MessageBox} This message box
2969 prompt : function(title, msg, fn, scope, multiline){
2973 buttons: this.OKCANCEL,
2978 multiline: multiline,
2985 * Button config that displays a single OK button
2990 * Button config that displays Yes and No buttons
2993 YESNO : {yes:true, no:true},
2995 * Button config that displays OK and Cancel buttons
2998 OKCANCEL : {ok:true, cancel:true},
3000 * Button config that displays Yes, No and Cancel buttons
3003 YESNOCANCEL : {yes:true, no:true, cancel:true},
3006 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3009 defaultTextHeight : 75,
3011 * The maximum width in pixels of the message box (defaults to 600)
3016 * The minimum width in pixels of the message box (defaults to 100)
3021 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3022 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3025 minProgressWidth : 250,
3027 * An object containing the default button text strings that can be overriden for localized language support.
3028 * Supported properties are: ok, cancel, yes and no.
3029 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3042 * Shorthand for {@link Roo.MessageBox}
3044 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3045 Roo.Msg = Roo.Msg || Roo.MessageBox;
3054 * @class Roo.bootstrap.Navbar
3055 * @extends Roo.bootstrap.Component
3056 * Bootstrap Navbar class
3059 * Create a new Navbar
3060 * @param {Object} config The config object
3064 Roo.bootstrap.Navbar = function(config){
3065 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3069 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3078 getAutoCreate : function(){
3081 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3085 initEvents :function ()
3087 //Roo.log(this.el.select('.navbar-toggle',true));
3088 this.el.select('.navbar-toggle',true).on('click', function() {
3089 // Roo.log('click');
3090 this.el.select('.navbar-collapse',true).toggleClass('in');
3098 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3100 var size = this.el.getSize();
3101 this.maskEl.setSize(size.width, size.height);
3102 this.maskEl.enableDisplayMode("block");
3111 getChildContainer : function()
3113 if (this.el.select('.collapse').getCount()) {
3114 return this.el.select('.collapse',true).first();
3147 * @class Roo.bootstrap.NavSimplebar
3148 * @extends Roo.bootstrap.Navbar
3149 * Bootstrap Sidebar class
3151 * @cfg {Boolean} inverse is inverted color
3153 * @cfg {String} type (nav | pills | tabs)
3154 * @cfg {Boolean} arrangement stacked | justified
3155 * @cfg {String} align (left | right) alignment
3157 * @cfg {Boolean} main (true|false) main nav bar? default false
3158 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3160 * @cfg {String} tag (header|footer|nav|div) default is nav
3166 * Create a new Sidebar
3167 * @param {Object} config The config object
3171 Roo.bootstrap.NavSimplebar = function(config){
3172 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3175 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3191 getAutoCreate : function(){
3195 tag : this.tag || 'div',
3208 this.type = this.type || 'nav';
3209 if (['tabs','pills'].indexOf(this.type)!==-1) {
3210 cfg.cn[0].cls += ' nav-' + this.type
3214 if (this.type!=='nav') {
3215 Roo.log('nav type must be nav/tabs/pills')
3217 cfg.cn[0].cls += ' navbar-nav'
3223 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3224 cfg.cn[0].cls += ' nav-' + this.arrangement;
3228 if (this.align === 'right') {
3229 cfg.cn[0].cls += ' navbar-right';
3233 cfg.cls += ' navbar-inverse';
3260 * @class Roo.bootstrap.NavHeaderbar
3261 * @extends Roo.bootstrap.NavSimplebar
3262 * Bootstrap Sidebar class
3264 * @cfg {String} brand what is brand
3265 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3266 * @cfg {String} brand_href href of the brand
3267 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3268 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3269 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3270 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3273 * Create a new Sidebar
3274 * @param {Object} config The config object
3278 Roo.bootstrap.NavHeaderbar = function(config){
3279 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3283 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3290 desktopCenter : false,
3293 getAutoCreate : function(){
3296 tag: this.nav || 'nav',
3303 if (this.desktopCenter) {
3304 cn.push({cls : 'container', cn : []});
3311 cls: 'navbar-header',
3316 cls: 'navbar-toggle',
3317 'data-toggle': 'collapse',
3322 html: 'Toggle navigation'
3344 cls: 'collapse navbar-collapse',
3348 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3350 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3351 cfg.cls += ' navbar-' + this.position;
3353 // tag can override this..
3355 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3358 if (this.brand !== '') {
3361 href: this.brand_href ? this.brand_href : '#',
3362 cls: 'navbar-brand',
3370 cfg.cls += ' main-nav';
3378 getHeaderChildContainer : function()
3380 if (this.el.select('.navbar-header').getCount()) {
3381 return this.el.select('.navbar-header',true).first();
3384 return this.getChildContainer();
3388 initEvents : function()
3390 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3392 if (this.autohide) {
3397 Roo.get(document).on('scroll',function(e) {
3398 var ns = Roo.get(document).getScroll().top;
3399 var os = prevScroll;
3403 ft.removeClass('slideDown');
3404 ft.addClass('slideUp');
3407 ft.removeClass('slideUp');
3408 ft.addClass('slideDown');
3432 * @class Roo.bootstrap.NavSidebar
3433 * @extends Roo.bootstrap.Navbar
3434 * Bootstrap Sidebar class
3437 * Create a new Sidebar
3438 * @param {Object} config The config object
3442 Roo.bootstrap.NavSidebar = function(config){
3443 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3446 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3448 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3450 getAutoCreate : function(){
3455 cls: 'sidebar sidebar-nav'
3477 * @class Roo.bootstrap.NavGroup
3478 * @extends Roo.bootstrap.Component
3479 * Bootstrap NavGroup class
3480 * @cfg {String} align left | right
3481 * @cfg {Boolean} inverse false | true
3482 * @cfg {String} type (nav|pills|tab) default nav
3483 * @cfg {String} navId - reference Id for navbar.
3487 * Create a new nav group
3488 * @param {Object} config The config object
3491 Roo.bootstrap.NavGroup = function(config){
3492 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3495 Roo.bootstrap.NavGroup.register(this);
3499 * Fires when the active item changes
3500 * @param {Roo.bootstrap.NavGroup} this
3501 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3502 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3509 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3520 getAutoCreate : function()
3522 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3529 if (['tabs','pills'].indexOf(this.type)!==-1) {
3530 cfg.cls += ' nav-' + this.type
3532 if (this.type!=='nav') {
3533 Roo.log('nav type must be nav/tabs/pills')
3535 cfg.cls += ' navbar-nav'
3538 if (this.parent().sidebar) {
3541 cls: 'dashboard-menu sidebar-menu'
3547 if (this.form === true) {
3553 if (this.align === 'right') {
3554 cfg.cls += ' navbar-right';
3556 cfg.cls += ' navbar-left';
3560 if (this.align === 'right') {
3561 cfg.cls += ' navbar-right';
3565 cfg.cls += ' navbar-inverse';
3573 * sets the active Navigation item
3574 * @param {Roo.bootstrap.NavItem} the new current navitem
3576 setActiveItem : function(item)
3579 Roo.each(this.navItems, function(v){
3584 v.setActive(false, true);
3591 item.setActive(true, true);
3592 this.fireEvent('changed', this, item, prev);
3597 * gets the active Navigation item
3598 * @return {Roo.bootstrap.NavItem} the current navitem
3600 getActive : function()
3604 Roo.each(this.navItems, function(v){
3615 indexOfNav : function()
3619 Roo.each(this.navItems, function(v,i){
3630 * adds a Navigation item
3631 * @param {Roo.bootstrap.NavItem} the navitem to add
3633 addItem : function(cfg)
3635 var cn = new Roo.bootstrap.NavItem(cfg);
3637 cn.parentId = this.id;
3638 cn.onRender(this.el, null);
3642 * register a Navigation item
3643 * @param {Roo.bootstrap.NavItem} the navitem to add
3645 register : function(item)
3647 this.navItems.push( item);
3648 item.navId = this.navId;
3653 * clear all the Navigation item
3656 clearAll : function()
3659 this.el.dom.innerHTML = '';
3662 getNavItem: function(tabId)
3665 Roo.each(this.navItems, function(e) {
3666 if (e.tabId == tabId) {
3676 setActiveNext : function()
3678 var i = this.indexOfNav(this.getActive());
3679 if (i > this.navItems.length) {
3682 this.setActiveItem(this.navItems[i+1]);
3684 setActivePrev : function()
3686 var i = this.indexOfNav(this.getActive());
3690 this.setActiveItem(this.navItems[i-1]);
3692 clearWasActive : function(except) {
3693 Roo.each(this.navItems, function(e) {
3694 if (e.tabId != except.tabId && e.was_active) {
3695 e.was_active = false;
3702 getWasActive : function ()
3705 Roo.each(this.navItems, function(e) {
3720 Roo.apply(Roo.bootstrap.NavGroup, {
3724 * register a Navigation Group
3725 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3727 register : function(navgrp)
3729 this.groups[navgrp.navId] = navgrp;
3733 * fetch a Navigation Group based on the navigation ID
3734 * @param {string} the navgroup to add
3735 * @returns {Roo.bootstrap.NavGroup} the navgroup
3737 get: function(navId) {
3738 if (typeof(this.groups[navId]) == 'undefined') {
3740 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3742 return this.groups[navId] ;
3757 * @class Roo.bootstrap.NavItem
3758 * @extends Roo.bootstrap.Component
3759 * Bootstrap Navbar.NavItem class
3760 * @cfg {String} href link to
3761 * @cfg {String} html content of button
3762 * @cfg {String} badge text inside badge
3763 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3764 * @cfg {String} glyphicon name of glyphicon
3765 * @cfg {String} icon name of font awesome icon
3766 * @cfg {Boolean} active Is item active
3767 * @cfg {Boolean} disabled Is item disabled
3769 * @cfg {Boolean} preventDefault (true | false) default false
3770 * @cfg {String} tabId the tab that this item activates.
3771 * @cfg {String} tagtype (a|span) render as a href or span?
3772 * @cfg {Boolean} animateRef (true|false) link to element default false
3775 * Create a new Navbar Item
3776 * @param {Object} config The config object
3778 Roo.bootstrap.NavItem = function(config){
3779 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3784 * The raw click event for the entire grid.
3785 * @param {Roo.EventObject} e
3790 * Fires when the active item active state changes
3791 * @param {Roo.bootstrap.NavItem} this
3792 * @param {boolean} state the new state
3798 * Fires when scroll to element
3799 * @param {Roo.bootstrap.NavItem} this
3800 * @param {Object} options
3801 * @param {Roo.EventObject} e
3809 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3817 preventDefault : false,
3824 getAutoCreate : function(){
3832 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3834 if (this.disabled) {
3835 cfg.cls += ' disabled';
3838 if (this.href || this.html || this.glyphicon || this.icon) {
3842 href : this.href || "#",
3843 html: this.html || ''
3848 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3851 if(this.glyphicon) {
3852 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3857 cfg.cn[0].html += " <span class='caret'></span>";
3861 if (this.badge !== '') {
3863 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3871 initEvents: function()
3873 if (typeof (this.menu) != 'undefined') {
3874 this.menu.parentType = this.xtype;
3875 this.menu.triggerEl = this.el;
3876 this.menu = this.addxtype(Roo.apply({}, this.menu));
3879 this.el.select('a',true).on('click', this.onClick, this);
3881 if(this.tagtype == 'span'){
3882 this.el.select('span',true).on('click', this.onClick, this);
3885 // at this point parent should be available..
3886 this.parent().register(this);
3889 onClick : function(e)
3892 this.preventDefault ||
3899 if (this.disabled) {
3903 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3904 if (tg && tg.transition) {
3905 Roo.log("waiting for the transitionend");
3911 //Roo.log("fire event clicked");
3912 if(this.fireEvent('click', this, e) === false){
3916 if(this.tagtype == 'span'){
3920 //Roo.log(this.href);
3921 var ael = this.el.select('a',true).first();
3924 if(ael && this.animateRef && this.href.indexOf('#') > -1){
3925 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
3926 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
3927 return; // ignore... - it's a 'hash' to another page.
3931 this.scrollToElement(e);
3935 var p = this.parent();
3937 if (['tabs','pills'].indexOf(p.type)!==-1) {
3938 if (typeof(p.setActiveItem) !== 'undefined') {
3939 p.setActiveItem(this);
3944 isActive: function () {
3947 setActive : function(state, fire, is_was_active)
3949 if (this.active && !state & this.navId) {
3950 this.was_active = true;
3951 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3953 nv.clearWasActive(this);
3957 this.active = state;
3960 this.el.removeClass('active');
3961 } else if (!this.el.hasClass('active')) {
3962 this.el.addClass('active');
3965 this.fireEvent('changed', this, state);
3968 // show a panel if it's registered and related..
3970 if (!this.navId || !this.tabId || !state || is_was_active) {
3974 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3978 var pan = tg.getPanelByName(this.tabId);
3982 // if we can not flip to new panel - go back to old nav highlight..
3983 if (false == tg.showPanel(pan)) {
3984 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3986 var onav = nv.getWasActive();
3988 onav.setActive(true, false, true);
3997 // this should not be here...
3998 setDisabled : function(state)
4000 this.disabled = state;
4002 this.el.removeClass('disabled');
4003 } else if (!this.el.hasClass('disabled')) {
4004 this.el.addClass('disabled');
4010 * Fetch the element to display the tooltip on.
4011 * @return {Roo.Element} defaults to this.el
4013 tooltipEl : function()
4015 return this.el.select('' + this.tagtype + '', true).first();
4018 scrollToElement : function(e)
4020 var c = document.body;
4022 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4028 var o = target.calcOffsetsTo(c);
4035 this.fireEvent('scrollto', this, options, e);
4037 Roo.get(c).scrollTo('top', options.value, true);
4050 * <span> icon </span>
4051 * <span> text </span>
4052 * <span>badge </span>
4056 * @class Roo.bootstrap.NavSidebarItem
4057 * @extends Roo.bootstrap.NavItem
4058 * Bootstrap Navbar.NavSidebarItem class
4060 * Create a new Navbar Button
4061 * @param {Object} config The config object
4063 Roo.bootstrap.NavSidebarItem = function(config){
4064 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4069 * The raw click event for the entire grid.
4070 * @param {Roo.EventObject} e
4075 * Fires when the active item active state changes
4076 * @param {Roo.bootstrap.NavSidebarItem} this
4077 * @param {boolean} state the new state
4085 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4088 getAutoCreate : function(){
4093 href : this.href || '#',
4105 html : this.html || ''
4110 cfg.cls += ' active';
4114 if (this.glyphicon || this.icon) {
4115 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4116 a.cn.push({ tag : 'i', cls : c }) ;
4121 if (this.badge !== '') {
4122 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4126 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4127 a.cls += 'dropdown-toggle treeview' ;
4151 * @class Roo.bootstrap.Row
4152 * @extends Roo.bootstrap.Component
4153 * Bootstrap Row class (contains columns...)
4157 * @param {Object} config The config object
4160 Roo.bootstrap.Row = function(config){
4161 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4164 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4166 getAutoCreate : function(){
4185 * @class Roo.bootstrap.Element
4186 * @extends Roo.bootstrap.Component
4187 * Bootstrap Element class
4188 * @cfg {String} html contents of the element
4189 * @cfg {String} tag tag of the element
4190 * @cfg {String} cls class of the element
4191 * @cfg {Boolean} preventDefault (true|false) default false
4192 * @cfg {Boolean} clickable (true|false) default false
4195 * Create a new Element
4196 * @param {Object} config The config object
4199 Roo.bootstrap.Element = function(config){
4200 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4206 * When a element is chick
4207 * @param {Roo.bootstrap.Element} this
4208 * @param {Roo.EventObject} e
4214 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4219 preventDefault: false,
4222 getAutoCreate : function(){
4233 initEvents: function()
4235 Roo.bootstrap.Element.superclass.initEvents.call(this);
4238 this.el.on('click', this.onClick, this);
4243 onClick : function(e)
4245 if(this.preventDefault){
4249 this.fireEvent('click', this, e);
4252 getValue : function()
4254 return this.el.dom.innerHTML;
4257 setValue : function(value)
4259 this.el.dom.innerHTML = value;
4274 * @class Roo.bootstrap.Pagination
4275 * @extends Roo.bootstrap.Component
4276 * Bootstrap Pagination class
4277 * @cfg {String} size xs | sm | md | lg
4278 * @cfg {Boolean} inverse false | true
4281 * Create a new Pagination
4282 * @param {Object} config The config object
4285 Roo.bootstrap.Pagination = function(config){
4286 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4289 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4295 getAutoCreate : function(){
4301 cfg.cls += ' inverse';
4307 cfg.cls += " " + this.cls;
4325 * @class Roo.bootstrap.PaginationItem
4326 * @extends Roo.bootstrap.Component
4327 * Bootstrap PaginationItem class
4328 * @cfg {String} html text
4329 * @cfg {String} href the link
4330 * @cfg {Boolean} preventDefault (true | false) default true
4331 * @cfg {Boolean} active (true | false) default false
4332 * @cfg {Boolean} disabled default false
4336 * Create a new PaginationItem
4337 * @param {Object} config The config object
4341 Roo.bootstrap.PaginationItem = function(config){
4342 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4347 * The raw click event for the entire grid.
4348 * @param {Roo.EventObject} e
4354 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4358 preventDefault: true,
4363 getAutoCreate : function(){
4369 href : this.href ? this.href : '#',
4370 html : this.html ? this.html : ''
4380 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4384 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4390 initEvents: function() {
4392 this.el.on('click', this.onClick, this);
4395 onClick : function(e)
4397 Roo.log('PaginationItem on click ');
4398 if(this.preventDefault){
4406 this.fireEvent('click', this, e);
4422 * @class Roo.bootstrap.Slider
4423 * @extends Roo.bootstrap.Component
4424 * Bootstrap Slider class
4427 * Create a new Slider
4428 * @param {Object} config The config object
4431 Roo.bootstrap.Slider = function(config){
4432 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4435 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4437 getAutoCreate : function(){
4441 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4445 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4457 * Ext JS Library 1.1.1
4458 * Copyright(c) 2006-2007, Ext JS, LLC.
4460 * Originally Released Under LGPL - original licence link has changed is not relivant.
4463 * <script type="text/javascript">
4468 * @class Roo.grid.ColumnModel
4469 * @extends Roo.util.Observable
4470 * This is the default implementation of a ColumnModel used by the Grid. It defines
4471 * the columns in the grid.
4474 var colModel = new Roo.grid.ColumnModel([
4475 {header: "Ticker", width: 60, sortable: true, locked: true},
4476 {header: "Company Name", width: 150, sortable: true},
4477 {header: "Market Cap.", width: 100, sortable: true},
4478 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4479 {header: "Employees", width: 100, sortable: true, resizable: false}
4484 * The config options listed for this class are options which may appear in each
4485 * individual column definition.
4486 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4488 * @param {Object} config An Array of column config objects. See this class's
4489 * config objects for details.
4491 Roo.grid.ColumnModel = function(config){
4493 * The config passed into the constructor
4495 this.config = config;
4498 // if no id, create one
4499 // if the column does not have a dataIndex mapping,
4500 // map it to the order it is in the config
4501 for(var i = 0, len = config.length; i < len; i++){
4503 if(typeof c.dataIndex == "undefined"){
4506 if(typeof c.renderer == "string"){
4507 c.renderer = Roo.util.Format[c.renderer];
4509 if(typeof c.id == "undefined"){
4512 if(c.editor && c.editor.xtype){
4513 c.editor = Roo.factory(c.editor, Roo.grid);
4515 if(c.editor && c.editor.isFormField){
4516 c.editor = new Roo.grid.GridEditor(c.editor);
4518 this.lookup[c.id] = c;
4522 * The width of columns which have no width specified (defaults to 100)
4525 this.defaultWidth = 100;
4528 * Default sortable of columns which have no sortable specified (defaults to false)
4531 this.defaultSortable = false;
4535 * @event widthchange
4536 * Fires when the width of a column changes.
4537 * @param {ColumnModel} this
4538 * @param {Number} columnIndex The column index
4539 * @param {Number} newWidth The new width
4541 "widthchange": true,
4543 * @event headerchange
4544 * Fires when the text of a header changes.
4545 * @param {ColumnModel} this
4546 * @param {Number} columnIndex The column index
4547 * @param {Number} newText The new header text
4549 "headerchange": true,
4551 * @event hiddenchange
4552 * Fires when a column is hidden or "unhidden".
4553 * @param {ColumnModel} this
4554 * @param {Number} columnIndex The column index
4555 * @param {Boolean} hidden true if hidden, false otherwise
4557 "hiddenchange": true,
4559 * @event columnmoved
4560 * Fires when a column is moved.
4561 * @param {ColumnModel} this
4562 * @param {Number} oldIndex
4563 * @param {Number} newIndex
4565 "columnmoved" : true,
4567 * @event columlockchange
4568 * Fires when a column's locked state is changed
4569 * @param {ColumnModel} this
4570 * @param {Number} colIndex
4571 * @param {Boolean} locked true if locked
4573 "columnlockchange" : true
4575 Roo.grid.ColumnModel.superclass.constructor.call(this);
4577 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4579 * @cfg {String} header The header text to display in the Grid view.
4582 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4583 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4584 * specified, the column's index is used as an index into the Record's data Array.
4587 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4588 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4591 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4592 * Defaults to the value of the {@link #defaultSortable} property.
4593 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4596 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4599 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4602 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4605 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4608 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4609 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4610 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4611 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4614 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4617 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4620 * @cfg {String} cursor (Optional)
4623 * @cfg {String} tooltip (Optional)
4626 * Returns the id of the column at the specified index.
4627 * @param {Number} index The column index
4628 * @return {String} the id
4630 getColumnId : function(index){
4631 return this.config[index].id;
4635 * Returns the column for a specified id.
4636 * @param {String} id The column id
4637 * @return {Object} the column
4639 getColumnById : function(id){
4640 return this.lookup[id];
4645 * Returns the column for a specified dataIndex.
4646 * @param {String} dataIndex The column dataIndex
4647 * @return {Object|Boolean} the column or false if not found
4649 getColumnByDataIndex: function(dataIndex){
4650 var index = this.findColumnIndex(dataIndex);
4651 return index > -1 ? this.config[index] : false;
4655 * Returns the index for a specified column id.
4656 * @param {String} id The column id
4657 * @return {Number} the index, or -1 if not found
4659 getIndexById : function(id){
4660 for(var i = 0, len = this.config.length; i < len; i++){
4661 if(this.config[i].id == id){
4669 * Returns the index for a specified column dataIndex.
4670 * @param {String} dataIndex The column dataIndex
4671 * @return {Number} the index, or -1 if not found
4674 findColumnIndex : function(dataIndex){
4675 for(var i = 0, len = this.config.length; i < len; i++){
4676 if(this.config[i].dataIndex == dataIndex){
4684 moveColumn : function(oldIndex, newIndex){
4685 var c = this.config[oldIndex];
4686 this.config.splice(oldIndex, 1);
4687 this.config.splice(newIndex, 0, c);
4688 this.dataMap = null;
4689 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4692 isLocked : function(colIndex){
4693 return this.config[colIndex].locked === true;
4696 setLocked : function(colIndex, value, suppressEvent){
4697 if(this.isLocked(colIndex) == value){
4700 this.config[colIndex].locked = value;
4702 this.fireEvent("columnlockchange", this, colIndex, value);
4706 getTotalLockedWidth : function(){
4708 for(var i = 0; i < this.config.length; i++){
4709 if(this.isLocked(i) && !this.isHidden(i)){
4710 this.totalWidth += this.getColumnWidth(i);
4716 getLockedCount : function(){
4717 for(var i = 0, len = this.config.length; i < len; i++){
4718 if(!this.isLocked(i)){
4725 * Returns the number of columns.
4728 getColumnCount : function(visibleOnly){
4729 if(visibleOnly === true){
4731 for(var i = 0, len = this.config.length; i < len; i++){
4732 if(!this.isHidden(i)){
4738 return this.config.length;
4742 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4743 * @param {Function} fn
4744 * @param {Object} scope (optional)
4745 * @return {Array} result
4747 getColumnsBy : function(fn, scope){
4749 for(var i = 0, len = this.config.length; i < len; i++){
4750 var c = this.config[i];
4751 if(fn.call(scope||this, c, i) === true){
4759 * Returns true if the specified column is sortable.
4760 * @param {Number} col The column index
4763 isSortable : function(col){
4764 if(typeof this.config[col].sortable == "undefined"){
4765 return this.defaultSortable;
4767 return this.config[col].sortable;
4771 * Returns the rendering (formatting) function defined for the column.
4772 * @param {Number} col The column index.
4773 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4775 getRenderer : function(col){
4776 if(!this.config[col].renderer){
4777 return Roo.grid.ColumnModel.defaultRenderer;
4779 return this.config[col].renderer;
4783 * Sets the rendering (formatting) function for a column.
4784 * @param {Number} col The column index
4785 * @param {Function} fn The function to use to process the cell's raw data
4786 * to return HTML markup for the grid view. The render function is called with
4787 * the following parameters:<ul>
4788 * <li>Data value.</li>
4789 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4790 * <li>css A CSS style string to apply to the table cell.</li>
4791 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4792 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4793 * <li>Row index</li>
4794 * <li>Column index</li>
4795 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4797 setRenderer : function(col, fn){
4798 this.config[col].renderer = fn;
4802 * Returns the width for the specified column.
4803 * @param {Number} col The column index
4806 getColumnWidth : function(col){
4807 return this.config[col].width * 1 || this.defaultWidth;
4811 * Sets the width for a column.
4812 * @param {Number} col The column index
4813 * @param {Number} width The new width
4815 setColumnWidth : function(col, width, suppressEvent){
4816 this.config[col].width = width;
4817 this.totalWidth = null;
4819 this.fireEvent("widthchange", this, col, width);
4824 * Returns the total width of all columns.
4825 * @param {Boolean} includeHidden True to include hidden column widths
4828 getTotalWidth : function(includeHidden){
4829 if(!this.totalWidth){
4830 this.totalWidth = 0;
4831 for(var i = 0, len = this.config.length; i < len; i++){
4832 if(includeHidden || !this.isHidden(i)){
4833 this.totalWidth += this.getColumnWidth(i);
4837 return this.totalWidth;
4841 * Returns the header for the specified column.
4842 * @param {Number} col The column index
4845 getColumnHeader : function(col){
4846 return this.config[col].header;
4850 * Sets the header for a column.
4851 * @param {Number} col The column index
4852 * @param {String} header The new header
4854 setColumnHeader : function(col, header){
4855 this.config[col].header = header;
4856 this.fireEvent("headerchange", this, col, header);
4860 * Returns the tooltip for the specified column.
4861 * @param {Number} col The column index
4864 getColumnTooltip : function(col){
4865 return this.config[col].tooltip;
4868 * Sets the tooltip for a column.
4869 * @param {Number} col The column index
4870 * @param {String} tooltip The new tooltip
4872 setColumnTooltip : function(col, tooltip){
4873 this.config[col].tooltip = tooltip;
4877 * Returns the dataIndex for the specified column.
4878 * @param {Number} col The column index
4881 getDataIndex : function(col){
4882 return this.config[col].dataIndex;
4886 * Sets the dataIndex for a column.
4887 * @param {Number} col The column index
4888 * @param {Number} dataIndex The new dataIndex
4890 setDataIndex : function(col, dataIndex){
4891 this.config[col].dataIndex = dataIndex;
4897 * Returns true if the cell is editable.
4898 * @param {Number} colIndex The column index
4899 * @param {Number} rowIndex The row index
4902 isCellEditable : function(colIndex, rowIndex){
4903 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4907 * Returns the editor defined for the cell/column.
4908 * return false or null to disable editing.
4909 * @param {Number} colIndex The column index
4910 * @param {Number} rowIndex The row index
4913 getCellEditor : function(colIndex, rowIndex){
4914 return this.config[colIndex].editor;
4918 * Sets if a column is editable.
4919 * @param {Number} col The column index
4920 * @param {Boolean} editable True if the column is editable
4922 setEditable : function(col, editable){
4923 this.config[col].editable = editable;
4928 * Returns true if the column is hidden.
4929 * @param {Number} colIndex The column index
4932 isHidden : function(colIndex){
4933 return this.config[colIndex].hidden;
4938 * Returns true if the column width cannot be changed
4940 isFixed : function(colIndex){
4941 return this.config[colIndex].fixed;
4945 * Returns true if the column can be resized
4948 isResizable : function(colIndex){
4949 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4952 * Sets if a column is hidden.
4953 * @param {Number} colIndex The column index
4954 * @param {Boolean} hidden True if the column is hidden
4956 setHidden : function(colIndex, hidden){
4957 this.config[colIndex].hidden = hidden;
4958 this.totalWidth = null;
4959 this.fireEvent("hiddenchange", this, colIndex, hidden);
4963 * Sets the editor for a column.
4964 * @param {Number} col The column index
4965 * @param {Object} editor The editor object
4967 setEditor : function(col, editor){
4968 this.config[col].editor = editor;
4972 Roo.grid.ColumnModel.defaultRenderer = function(value){
4973 if(typeof value == "string" && value.length < 1){
4979 // Alias for backwards compatibility
4980 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4983 * Ext JS Library 1.1.1
4984 * Copyright(c) 2006-2007, Ext JS, LLC.
4986 * Originally Released Under LGPL - original licence link has changed is not relivant.
4989 * <script type="text/javascript">
4993 * @class Roo.LoadMask
4994 * A simple utility class for generically masking elements while loading data. If the element being masked has
4995 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4996 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4997 * element's UpdateManager load indicator and will be destroyed after the initial load.
4999 * Create a new LoadMask
5000 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5001 * @param {Object} config The config object
5003 Roo.LoadMask = function(el, config){
5004 this.el = Roo.get(el);
5005 Roo.apply(this, config);
5007 this.store.on('beforeload', this.onBeforeLoad, this);
5008 this.store.on('load', this.onLoad, this);
5009 this.store.on('loadexception', this.onLoadException, this);
5010 this.removeMask = false;
5012 var um = this.el.getUpdateManager();
5013 um.showLoadIndicator = false; // disable the default indicator
5014 um.on('beforeupdate', this.onBeforeLoad, this);
5015 um.on('update', this.onLoad, this);
5016 um.on('failure', this.onLoad, this);
5017 this.removeMask = true;
5021 Roo.LoadMask.prototype = {
5023 * @cfg {Boolean} removeMask
5024 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5025 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5029 * The text to display in a centered loading message box (defaults to 'Loading...')
5033 * @cfg {String} msgCls
5034 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5036 msgCls : 'x-mask-loading',
5039 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5045 * Disables the mask to prevent it from being displayed
5047 disable : function(){
5048 this.disabled = true;
5052 * Enables the mask so that it can be displayed
5054 enable : function(){
5055 this.disabled = false;
5058 onLoadException : function()
5062 if (typeof(arguments[3]) != 'undefined') {
5063 Roo.MessageBox.alert("Error loading",arguments[3]);
5067 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5068 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5077 this.el.unmask(this.removeMask);
5082 this.el.unmask(this.removeMask);
5086 onBeforeLoad : function(){
5088 this.el.mask(this.msg, this.msgCls);
5093 destroy : function(){
5095 this.store.un('beforeload', this.onBeforeLoad, this);
5096 this.store.un('load', this.onLoad, this);
5097 this.store.un('loadexception', this.onLoadException, this);
5099 var um = this.el.getUpdateManager();
5100 um.un('beforeupdate', this.onBeforeLoad, this);
5101 um.un('update', this.onLoad, this);
5102 um.un('failure', this.onLoad, this);
5113 * @class Roo.bootstrap.Table
5114 * @extends Roo.bootstrap.Component
5115 * Bootstrap Table class
5116 * @cfg {String} cls table class
5117 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5118 * @cfg {String} bgcolor Specifies the background color for a table
5119 * @cfg {Number} border Specifies whether the table cells should have borders or not
5120 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5121 * @cfg {Number} cellspacing Specifies the space between cells
5122 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5123 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5124 * @cfg {String} sortable Specifies that the table should be sortable
5125 * @cfg {String} summary Specifies a summary of the content of a table
5126 * @cfg {Number} width Specifies the width of a table
5127 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5129 * @cfg {boolean} striped Should the rows be alternative striped
5130 * @cfg {boolean} bordered Add borders to the table
5131 * @cfg {boolean} hover Add hover highlighting
5132 * @cfg {boolean} condensed Format condensed
5133 * @cfg {boolean} responsive Format condensed
5134 * @cfg {Boolean} loadMask (true|false) default false
5135 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5136 * @cfg {Boolean} thead (true|false) generate thead, default true
5137 * @cfg {Boolean} RowSelection (true|false) default false
5138 * @cfg {Boolean} CellSelection (true|false) default false
5139 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5143 * Create a new Table
5144 * @param {Object} config The config object
5147 Roo.bootstrap.Table = function(config){
5148 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5151 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5152 this.sm = this.selModel;
5153 this.sm.xmodule = this.xmodule || false;
5155 if (this.cm && typeof(this.cm.config) == 'undefined') {
5156 this.colModel = new Roo.grid.ColumnModel(this.cm);
5157 this.cm = this.colModel;
5158 this.cm.xmodule = this.xmodule || false;
5161 this.store= Roo.factory(this.store, Roo.data);
5162 this.ds = this.store;
5163 this.ds.xmodule = this.xmodule || false;
5166 if (this.footer && this.store) {
5167 this.footer.dataSource = this.ds;
5168 this.footer = Roo.factory(this.footer);
5175 * Fires when a cell is clicked
5176 * @param {Roo.bootstrap.Table} this
5177 * @param {Roo.Element} el
5178 * @param {Number} rowIndex
5179 * @param {Number} columnIndex
5180 * @param {Roo.EventObject} e
5184 * @event celldblclick
5185 * Fires when a cell is double clicked
5186 * @param {Roo.bootstrap.Table} this
5187 * @param {Roo.Element} el
5188 * @param {Number} rowIndex
5189 * @param {Number} columnIndex
5190 * @param {Roo.EventObject} e
5192 "celldblclick" : true,
5195 * Fires when a row is clicked
5196 * @param {Roo.bootstrap.Table} this
5197 * @param {Roo.Element} el
5198 * @param {Number} rowIndex
5199 * @param {Roo.EventObject} e
5203 * @event rowdblclick
5204 * Fires when a row is double clicked
5205 * @param {Roo.bootstrap.Table} this
5206 * @param {Roo.Element} el
5207 * @param {Number} rowIndex
5208 * @param {Roo.EventObject} e
5210 "rowdblclick" : true,
5213 * Fires when a mouseover occur
5214 * @param {Roo.bootstrap.Table} this
5215 * @param {Roo.Element} el
5216 * @param {Number} rowIndex
5217 * @param {Number} columnIndex
5218 * @param {Roo.EventObject} e
5223 * Fires when a mouseout occur
5224 * @param {Roo.bootstrap.Table} this
5225 * @param {Roo.Element} el
5226 * @param {Number} rowIndex
5227 * @param {Number} columnIndex
5228 * @param {Roo.EventObject} e
5233 * Fires when a row is rendered, so you can change add a style to it.
5234 * @param {Roo.bootstrap.Table} this
5235 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5239 * @event rowsrendered
5240 * Fires when all the rows have been rendered
5241 * @param {Roo.bootstrap.Table} this
5243 'rowsrendered' : true
5248 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5272 RowSelection : false,
5273 CellSelection : false,
5276 // Roo.Element - the tbody
5279 getAutoCreate : function(){
5280 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5289 cfg.cls += ' table-striped';
5293 cfg.cls += ' table-hover';
5295 if (this.bordered) {
5296 cfg.cls += ' table-bordered';
5298 if (this.condensed) {
5299 cfg.cls += ' table-condensed';
5301 if (this.responsive) {
5302 cfg.cls += ' table-responsive';
5306 cfg.cls+= ' ' +this.cls;
5309 // this lot should be simplifed...
5312 cfg.align=this.align;
5315 cfg.bgcolor=this.bgcolor;
5318 cfg.border=this.border;
5320 if (this.cellpadding) {
5321 cfg.cellpadding=this.cellpadding;
5323 if (this.cellspacing) {
5324 cfg.cellspacing=this.cellspacing;
5327 cfg.frame=this.frame;
5330 cfg.rules=this.rules;
5332 if (this.sortable) {
5333 cfg.sortable=this.sortable;
5336 cfg.summary=this.summary;
5339 cfg.width=this.width;
5342 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5345 if(this.store || this.cm){
5347 cfg.cn.push(this.renderHeader());
5350 cfg.cn.push(this.renderBody());
5353 cfg.cn.push(this.renderFooter());
5356 cfg.cls+= ' TableGrid';
5359 return { cn : [ cfg ] };
5362 initEvents : function()
5364 if(!this.store || !this.cm){
5368 //Roo.log('initEvents with ds!!!!');
5370 this.mainBody = this.el.select('tbody', true).first();
5375 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5376 e.on('click', _this.sort, _this);
5379 this.el.on("click", this.onClick, this);
5380 this.el.on("dblclick", this.onDblClick, this);
5382 // why is this done????? = it breaks dialogs??
5383 //this.parent().el.setStyle('position', 'relative');
5387 this.footer.parentId = this.id;
5388 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5391 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5393 this.store.on('load', this.onLoad, this);
5394 this.store.on('beforeload', this.onBeforeLoad, this);
5395 this.store.on('update', this.onUpdate, this);
5396 this.store.on('add', this.onAdd, this);
5400 onMouseover : function(e, el)
5402 var cell = Roo.get(el);
5408 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5409 cell = cell.findParent('td', false, true);
5412 var row = cell.findParent('tr', false, true);
5413 var cellIndex = cell.dom.cellIndex;
5414 var rowIndex = row.dom.rowIndex - 1; // start from 0
5416 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5420 onMouseout : function(e, el)
5422 var cell = Roo.get(el);
5428 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5429 cell = cell.findParent('td', false, true);
5432 var row = cell.findParent('tr', false, true);
5433 var cellIndex = cell.dom.cellIndex;
5434 var rowIndex = row.dom.rowIndex - 1; // start from 0
5436 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5440 onClick : function(e, el)
5442 var cell = Roo.get(el);
5444 if(!cell || (!this.CellSelection && !this.RowSelection)){
5448 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5449 cell = cell.findParent('td', false, true);
5452 if(!cell || typeof(cell) == 'undefined'){
5456 var row = cell.findParent('tr', false, true);
5458 if(!row || typeof(row) == 'undefined'){
5462 var cellIndex = cell.dom.cellIndex;
5463 var rowIndex = this.getRowIndex(row);
5465 if(this.CellSelection){
5466 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5469 if(this.RowSelection){
5470 this.fireEvent('rowclick', this, row, rowIndex, e);
5476 onDblClick : function(e,el)
5478 var cell = Roo.get(el);
5480 if(!cell || (!this.CellSelection && !this.RowSelection)){
5484 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5485 cell = cell.findParent('td', false, true);
5488 if(!cell || typeof(cell) == 'undefined'){
5492 var row = cell.findParent('tr', false, true);
5494 if(!row || typeof(row) == 'undefined'){
5498 var cellIndex = cell.dom.cellIndex;
5499 var rowIndex = this.getRowIndex(row);
5501 if(this.CellSelection){
5502 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5505 if(this.RowSelection){
5506 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5510 sort : function(e,el)
5512 var col = Roo.get(el);
5514 if(!col.hasClass('sortable')){
5518 var sort = col.attr('sort');
5521 if(col.hasClass('glyphicon-arrow-up')){
5525 this.store.sortInfo = {field : sort, direction : dir};
5528 Roo.log("calling footer first");
5529 this.footer.onClick('first');
5532 this.store.load({ params : { start : 0 } });
5536 renderHeader : function()
5545 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5547 var config = cm.config[i];
5552 html: cm.getColumnHeader(i)
5555 if(typeof(config.tooltip) != 'undefined'){
5556 c.tooltip = config.tooltip;
5559 if(typeof(config.colspan) != 'undefined'){
5560 c.colspan = config.colspan;
5563 if(typeof(config.hidden) != 'undefined' && config.hidden){
5564 c.style += ' display:none;';
5567 if(typeof(config.dataIndex) != 'undefined'){
5568 c.sort = config.dataIndex;
5571 if(typeof(config.sortable) != 'undefined' && config.sortable){
5575 if(typeof(config.align) != 'undefined' && config.align.length){
5576 c.style += ' text-align:' + config.align + ';';
5579 if(typeof(config.width) != 'undefined'){
5580 c.style += ' width:' + config.width + 'px;';
5583 if(typeof(config.cls) != 'undefined'){
5584 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5593 renderBody : function()
5603 colspan : this.cm.getColumnCount()
5613 renderFooter : function()
5623 colspan : this.cm.getColumnCount()
5637 Roo.log('ds onload');
5642 var ds = this.store;
5644 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5645 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5647 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5648 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5651 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5652 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5656 var tbody = this.mainBody;
5658 if(ds.getCount() > 0){
5659 ds.data.each(function(d,rowIndex){
5660 var row = this.renderRow(cm, ds, rowIndex);
5662 tbody.createChild(row);
5666 if(row.cellObjects.length){
5667 Roo.each(row.cellObjects, function(r){
5668 _this.renderCellObject(r);
5675 Roo.each(this.el.select('tbody td', true).elements, function(e){
5676 e.on('mouseover', _this.onMouseover, _this);
5679 Roo.each(this.el.select('tbody td', true).elements, function(e){
5680 e.on('mouseout', _this.onMouseout, _this);
5682 this.fireEvent('rowsrendered', this);
5683 //if(this.loadMask){
5684 // this.maskEl.hide();
5689 onUpdate : function(ds,record)
5691 this.refreshRow(record);
5694 onRemove : function(ds, record, index, isUpdate){
5695 if(isUpdate !== true){
5696 this.fireEvent("beforerowremoved", this, index, record);
5698 var bt = this.mainBody.dom;
5700 var rows = this.el.select('tbody > tr', true).elements;
5702 if(typeof(rows[index]) != 'undefined'){
5703 bt.removeChild(rows[index].dom);
5706 // if(bt.rows[index]){
5707 // bt.removeChild(bt.rows[index]);
5710 if(isUpdate !== true){
5711 //this.stripeRows(index);
5712 //this.syncRowHeights(index, index);
5714 this.fireEvent("rowremoved", this, index, record);
5718 onAdd : function(ds, records, rowIndex)
5720 //Roo.log('on Add called');
5721 // - note this does not handle multiple adding very well..
5722 var bt = this.mainBody.dom;
5723 for (var i =0 ; i < records.length;i++) {
5724 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5725 //Roo.log(records[i]);
5726 //Roo.log(this.store.getAt(rowIndex+i));
5727 this.insertRow(this.store, rowIndex + i, false);
5734 refreshRow : function(record){
5735 var ds = this.store, index;
5736 if(typeof record == 'number'){
5738 record = ds.getAt(index);
5740 index = ds.indexOf(record);
5742 this.insertRow(ds, index, true);
5743 this.onRemove(ds, record, index+1, true);
5744 //this.syncRowHeights(index, index);
5746 this.fireEvent("rowupdated", this, index, record);
5749 insertRow : function(dm, rowIndex, isUpdate){
5752 this.fireEvent("beforerowsinserted", this, rowIndex);
5754 //var s = this.getScrollState();
5755 var row = this.renderRow(this.cm, this.store, rowIndex);
5756 // insert before rowIndex..
5757 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5761 if(row.cellObjects.length){
5762 Roo.each(row.cellObjects, function(r){
5763 _this.renderCellObject(r);
5768 this.fireEvent("rowsinserted", this, rowIndex);
5769 //this.syncRowHeights(firstRow, lastRow);
5770 //this.stripeRows(firstRow);
5777 getRowDom : function(rowIndex)
5779 var rows = this.el.select('tbody > tr', true).elements;
5781 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5784 // returns the object tree for a tr..
5787 renderRow : function(cm, ds, rowIndex)
5790 var d = ds.getAt(rowIndex);
5797 var cellObjects = [];
5799 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5800 var config = cm.config[i];
5802 var renderer = cm.getRenderer(i);
5806 if(typeof(renderer) !== 'undefined'){
5807 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5809 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5810 // and are rendered into the cells after the row is rendered - using the id for the element.
5812 if(typeof(value) === 'object'){
5822 rowIndex : rowIndex,
5827 this.fireEvent('rowclass', this, rowcfg);
5831 cls : rowcfg.rowClass,
5833 html: (typeof(value) === 'object') ? '' : value
5840 if(typeof(config.colspan) != 'undefined'){
5841 td.colspan = config.colspan;
5844 if(typeof(config.hidden) != 'undefined' && config.hidden){
5845 td.style += ' display:none;';
5848 if(typeof(config.align) != 'undefined' && config.align.length){
5849 td.style += ' text-align:' + config.align + ';';
5852 if(typeof(config.width) != 'undefined'){
5853 td.style += ' width:' + config.width + 'px;';
5856 if(typeof(config.cursor) != 'undefined'){
5857 td.style += ' cursor:' + config.cursor + ';';
5860 if(typeof(config.cls) != 'undefined'){
5861 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
5868 row.cellObjects = cellObjects;
5876 onBeforeLoad : function()
5878 //Roo.log('ds onBeforeLoad');
5882 //if(this.loadMask){
5883 // this.maskEl.show();
5891 this.el.select('tbody', true).first().dom.innerHTML = '';
5894 * Show or hide a row.
5895 * @param {Number} rowIndex to show or hide
5896 * @param {Boolean} state hide
5898 setRowVisibility : function(rowIndex, state)
5900 var bt = this.mainBody.dom;
5902 var rows = this.el.select('tbody > tr', true).elements;
5904 if(typeof(rows[rowIndex]) == 'undefined'){
5907 rows[rowIndex].dom.style.display = state ? '' : 'none';
5911 getSelectionModel : function(){
5913 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5915 return this.selModel;
5918 * Render the Roo.bootstrap object from renderder
5920 renderCellObject : function(r)
5924 var t = r.cfg.render(r.container);
5927 Roo.each(r.cfg.cn, function(c){
5929 container: t.getChildContainer(),
5932 _this.renderCellObject(child);
5937 getRowIndex : function(row)
5941 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5964 * @class Roo.bootstrap.TableCell
5965 * @extends Roo.bootstrap.Component
5966 * Bootstrap TableCell class
5967 * @cfg {String} html cell contain text
5968 * @cfg {String} cls cell class
5969 * @cfg {String} tag cell tag (td|th) default td
5970 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5971 * @cfg {String} align Aligns the content in a cell
5972 * @cfg {String} axis Categorizes cells
5973 * @cfg {String} bgcolor Specifies the background color of a cell
5974 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5975 * @cfg {Number} colspan Specifies the number of columns a cell should span
5976 * @cfg {String} headers Specifies one or more header cells a cell is related to
5977 * @cfg {Number} height Sets the height of a cell
5978 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5979 * @cfg {Number} rowspan Sets the number of rows a cell should span
5980 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5981 * @cfg {String} valign Vertical aligns the content in a cell
5982 * @cfg {Number} width Specifies the width of a cell
5985 * Create a new TableCell
5986 * @param {Object} config The config object
5989 Roo.bootstrap.TableCell = function(config){
5990 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5993 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6013 getAutoCreate : function(){
6014 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6034 cfg.align=this.align
6040 cfg.bgcolor=this.bgcolor
6043 cfg.charoff=this.charoff
6046 cfg.colspan=this.colspan
6049 cfg.headers=this.headers
6052 cfg.height=this.height
6055 cfg.nowrap=this.nowrap
6058 cfg.rowspan=this.rowspan
6061 cfg.scope=this.scope
6064 cfg.valign=this.valign
6067 cfg.width=this.width
6086 * @class Roo.bootstrap.TableRow
6087 * @extends Roo.bootstrap.Component
6088 * Bootstrap TableRow class
6089 * @cfg {String} cls row class
6090 * @cfg {String} align Aligns the content in a table row
6091 * @cfg {String} bgcolor Specifies a background color for a table row
6092 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6093 * @cfg {String} valign Vertical aligns the content in a table row
6096 * Create a new TableRow
6097 * @param {Object} config The config object
6100 Roo.bootstrap.TableRow = function(config){
6101 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6104 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6112 getAutoCreate : function(){
6113 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6123 cfg.align = this.align;
6126 cfg.bgcolor = this.bgcolor;
6129 cfg.charoff = this.charoff;
6132 cfg.valign = this.valign;
6150 * @class Roo.bootstrap.TableBody
6151 * @extends Roo.bootstrap.Component
6152 * Bootstrap TableBody class
6153 * @cfg {String} cls element class
6154 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6155 * @cfg {String} align Aligns the content inside the element
6156 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6157 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6160 * Create a new TableBody
6161 * @param {Object} config The config object
6164 Roo.bootstrap.TableBody = function(config){
6165 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6168 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6176 getAutoCreate : function(){
6177 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6191 cfg.align = this.align;
6194 cfg.charoff = this.charoff;
6197 cfg.valign = this.valign;
6204 // initEvents : function()
6211 // this.store = Roo.factory(this.store, Roo.data);
6212 // this.store.on('load', this.onLoad, this);
6214 // this.store.load();
6218 // onLoad: function ()
6220 // this.fireEvent('load', this);
6230 * Ext JS Library 1.1.1
6231 * Copyright(c) 2006-2007, Ext JS, LLC.
6233 * Originally Released Under LGPL - original licence link has changed is not relivant.
6236 * <script type="text/javascript">
6239 // as we use this in bootstrap.
6240 Roo.namespace('Roo.form');
6242 * @class Roo.form.Action
6243 * Internal Class used to handle form actions
6245 * @param {Roo.form.BasicForm} el The form element or its id
6246 * @param {Object} config Configuration options
6251 // define the action interface
6252 Roo.form.Action = function(form, options){
6254 this.options = options || {};
6257 * Client Validation Failed
6260 Roo.form.Action.CLIENT_INVALID = 'client';
6262 * Server Validation Failed
6265 Roo.form.Action.SERVER_INVALID = 'server';
6267 * Connect to Server Failed
6270 Roo.form.Action.CONNECT_FAILURE = 'connect';
6272 * Reading Data from Server Failed
6275 Roo.form.Action.LOAD_FAILURE = 'load';
6277 Roo.form.Action.prototype = {
6279 failureType : undefined,
6280 response : undefined,
6284 run : function(options){
6289 success : function(response){
6294 handleResponse : function(response){
6298 // default connection failure
6299 failure : function(response){
6301 this.response = response;
6302 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6303 this.form.afterAction(this, false);
6306 processResponse : function(response){
6307 this.response = response;
6308 if(!response.responseText){
6311 this.result = this.handleResponse(response);
6315 // utility functions used internally
6316 getUrl : function(appendParams){
6317 var url = this.options.url || this.form.url || this.form.el.dom.action;
6319 var p = this.getParams();
6321 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6327 getMethod : function(){
6328 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6331 getParams : function(){
6332 var bp = this.form.baseParams;
6333 var p = this.options.params;
6335 if(typeof p == "object"){
6336 p = Roo.urlEncode(Roo.applyIf(p, bp));
6337 }else if(typeof p == 'string' && bp){
6338 p += '&' + Roo.urlEncode(bp);
6341 p = Roo.urlEncode(bp);
6346 createCallback : function(){
6348 success: this.success,
6349 failure: this.failure,
6351 timeout: (this.form.timeout*1000),
6352 upload: this.form.fileUpload ? this.success : undefined
6357 Roo.form.Action.Submit = function(form, options){
6358 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6361 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6364 haveProgress : false,
6365 uploadComplete : false,
6367 // uploadProgress indicator.
6368 uploadProgress : function()
6370 if (!this.form.progressUrl) {
6374 if (!this.haveProgress) {
6375 Roo.MessageBox.progress("Uploading", "Uploading");
6377 if (this.uploadComplete) {
6378 Roo.MessageBox.hide();
6382 this.haveProgress = true;
6384 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6386 var c = new Roo.data.Connection();
6388 url : this.form.progressUrl,
6393 success : function(req){
6394 //console.log(data);
6398 rdata = Roo.decode(req.responseText)
6400 Roo.log("Invalid data from server..");
6404 if (!rdata || !rdata.success) {
6406 Roo.MessageBox.alert(Roo.encode(rdata));
6409 var data = rdata.data;
6411 if (this.uploadComplete) {
6412 Roo.MessageBox.hide();
6417 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6418 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6421 this.uploadProgress.defer(2000,this);
6424 failure: function(data) {
6425 Roo.log('progress url failed ');
6436 // run get Values on the form, so it syncs any secondary forms.
6437 this.form.getValues();
6439 var o = this.options;
6440 var method = this.getMethod();
6441 var isPost = method == 'POST';
6442 if(o.clientValidation === false || this.form.isValid()){
6444 if (this.form.progressUrl) {
6445 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6446 (new Date() * 1) + '' + Math.random());
6451 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6452 form:this.form.el.dom,
6453 url:this.getUrl(!isPost),
6455 params:isPost ? this.getParams() : null,
6456 isUpload: this.form.fileUpload
6459 this.uploadProgress();
6461 }else if (o.clientValidation !== false){ // client validation failed
6462 this.failureType = Roo.form.Action.CLIENT_INVALID;
6463 this.form.afterAction(this, false);
6467 success : function(response)
6469 this.uploadComplete= true;
6470 if (this.haveProgress) {
6471 Roo.MessageBox.hide();
6475 var result = this.processResponse(response);
6476 if(result === true || result.success){
6477 this.form.afterAction(this, true);
6481 this.form.markInvalid(result.errors);
6482 this.failureType = Roo.form.Action.SERVER_INVALID;
6484 this.form.afterAction(this, false);
6486 failure : function(response)
6488 this.uploadComplete= true;
6489 if (this.haveProgress) {
6490 Roo.MessageBox.hide();
6493 this.response = response;
6494 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6495 this.form.afterAction(this, false);
6498 handleResponse : function(response){
6499 if(this.form.errorReader){
6500 var rs = this.form.errorReader.read(response);
6503 for(var i = 0, len = rs.records.length; i < len; i++) {
6504 var r = rs.records[i];
6508 if(errors.length < 1){
6512 success : rs.success,
6518 ret = Roo.decode(response.responseText);
6522 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6532 Roo.form.Action.Load = function(form, options){
6533 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6534 this.reader = this.form.reader;
6537 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6542 Roo.Ajax.request(Roo.apply(
6543 this.createCallback(), {
6544 method:this.getMethod(),
6545 url:this.getUrl(false),
6546 params:this.getParams()
6550 success : function(response){
6552 var result = this.processResponse(response);
6553 if(result === true || !result.success || !result.data){
6554 this.failureType = Roo.form.Action.LOAD_FAILURE;
6555 this.form.afterAction(this, false);
6558 this.form.clearInvalid();
6559 this.form.setValues(result.data);
6560 this.form.afterAction(this, true);
6563 handleResponse : function(response){
6564 if(this.form.reader){
6565 var rs = this.form.reader.read(response);
6566 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6568 success : rs.success,
6572 return Roo.decode(response.responseText);
6576 Roo.form.Action.ACTION_TYPES = {
6577 'load' : Roo.form.Action.Load,
6578 'submit' : Roo.form.Action.Submit
6587 * @class Roo.bootstrap.Form
6588 * @extends Roo.bootstrap.Component
6589 * Bootstrap Form class
6590 * @cfg {String} method GET | POST (default POST)
6591 * @cfg {String} labelAlign top | left (default top)
6592 * @cfg {String} align left | right - for navbars
6593 * @cfg {Boolean} loadMask load mask when submit (default true)
6598 * @param {Object} config The config object
6602 Roo.bootstrap.Form = function(config){
6603 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6606 * @event clientvalidation
6607 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6608 * @param {Form} this
6609 * @param {Boolean} valid true if the form has passed client-side validation
6611 clientvalidation: true,
6613 * @event beforeaction
6614 * Fires before any action is performed. Return false to cancel the action.
6615 * @param {Form} this
6616 * @param {Action} action The action to be performed
6620 * @event actionfailed
6621 * Fires when an action fails.
6622 * @param {Form} this
6623 * @param {Action} action The action that failed
6625 actionfailed : true,
6627 * @event actioncomplete
6628 * Fires when an action is completed.
6629 * @param {Form} this
6630 * @param {Action} action The action that completed
6632 actioncomplete : true
6637 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6640 * @cfg {String} method
6641 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6646 * The URL to use for form actions if one isn't supplied in the action options.
6649 * @cfg {Boolean} fileUpload
6650 * Set to true if this form is a file upload.
6654 * @cfg {Object} baseParams
6655 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6659 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6663 * @cfg {Sting} align (left|right) for navbar forms
6668 activeAction : null,
6671 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6672 * element by passing it or its id or mask the form itself by passing in true.
6675 waitMsgTarget : false,
6679 getAutoCreate : function(){
6683 method : this.method || 'POST',
6684 id : this.id || Roo.id(),
6687 if (this.parent().xtype.match(/^Nav/)) {
6688 cfg.cls = 'navbar-form navbar-' + this.align;
6692 if (this.labelAlign == 'left' ) {
6693 cfg.cls += ' form-horizontal';
6699 initEvents : function()
6701 this.el.on('submit', this.onSubmit, this);
6702 // this was added as random key presses on the form where triggering form submit.
6703 this.el.on('keypress', function(e) {
6704 if (e.getCharCode() != 13) {
6707 // we might need to allow it for textareas.. and some other items.
6708 // check e.getTarget().
6710 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6714 Roo.log("keypress blocked");
6722 onSubmit : function(e){
6727 * Returns true if client-side validation on the form is successful.
6730 isValid : function(){
6731 var items = this.getItems();
6733 items.each(function(f){
6742 * Returns true if any fields in this form have changed since their original load.
6745 isDirty : function(){
6747 var items = this.getItems();
6748 items.each(function(f){
6758 * Performs a predefined action (submit or load) or custom actions you define on this form.
6759 * @param {String} actionName The name of the action type
6760 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6761 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6762 * accept other config options):
6764 Property Type Description
6765 ---------------- --------------- ----------------------------------------------------------------------------------
6766 url String The url for the action (defaults to the form's url)
6767 method String The form method to use (defaults to the form's method, or POST if not defined)
6768 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6769 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6770 validate the form on the client (defaults to false)
6772 * @return {BasicForm} this
6774 doAction : function(action, options){
6775 if(typeof action == 'string'){
6776 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6778 if(this.fireEvent('beforeaction', this, action) !== false){
6779 this.beforeAction(action);
6780 action.run.defer(100, action);
6786 beforeAction : function(action){
6787 var o = action.options;
6790 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6792 // not really supported yet.. ??
6794 //if(this.waitMsgTarget === true){
6795 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6796 //}else if(this.waitMsgTarget){
6797 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6798 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6800 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6806 afterAction : function(action, success){
6807 this.activeAction = null;
6808 var o = action.options;
6810 //if(this.waitMsgTarget === true){
6812 //}else if(this.waitMsgTarget){
6813 // this.waitMsgTarget.unmask();
6815 // Roo.MessageBox.updateProgress(1);
6816 // Roo.MessageBox.hide();
6823 Roo.callback(o.success, o.scope, [this, action]);
6824 this.fireEvent('actioncomplete', this, action);
6828 // failure condition..
6829 // we have a scenario where updates need confirming.
6830 // eg. if a locking scenario exists..
6831 // we look for { errors : { needs_confirm : true }} in the response.
6833 (typeof(action.result) != 'undefined') &&
6834 (typeof(action.result.errors) != 'undefined') &&
6835 (typeof(action.result.errors.needs_confirm) != 'undefined')
6838 Roo.log("not supported yet");
6841 Roo.MessageBox.confirm(
6842 "Change requires confirmation",
6843 action.result.errorMsg,
6848 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6858 Roo.callback(o.failure, o.scope, [this, action]);
6859 // show an error message if no failed handler is set..
6860 if (!this.hasListener('actionfailed')) {
6861 Roo.log("need to add dialog support");
6863 Roo.MessageBox.alert("Error",
6864 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6865 action.result.errorMsg :
6866 "Saving Failed, please check your entries or try again"
6871 this.fireEvent('actionfailed', this, action);
6876 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6877 * @param {String} id The value to search for
6880 findField : function(id){
6881 var items = this.getItems();
6882 var field = items.get(id);
6884 items.each(function(f){
6885 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6892 return field || null;
6895 * Mark fields in this form invalid in bulk.
6896 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6897 * @return {BasicForm} this
6899 markInvalid : function(errors){
6900 if(errors instanceof Array){
6901 for(var i = 0, len = errors.length; i < len; i++){
6902 var fieldError = errors[i];
6903 var f = this.findField(fieldError.id);
6905 f.markInvalid(fieldError.msg);
6911 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6912 field.markInvalid(errors[id]);
6916 //Roo.each(this.childForms || [], function (f) {
6917 // f.markInvalid(errors);
6924 * Set values for fields in this form in bulk.
6925 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6926 * @return {BasicForm} this
6928 setValues : function(values){
6929 if(values instanceof Array){ // array of objects
6930 for(var i = 0, len = values.length; i < len; i++){
6932 var f = this.findField(v.id);
6934 f.setValue(v.value);
6935 if(this.trackResetOnLoad){
6936 f.originalValue = f.getValue();
6940 }else{ // object hash
6943 if(typeof values[id] != 'function' && (field = this.findField(id))){
6945 if (field.setFromData &&
6947 field.displayField &&
6948 // combos' with local stores can
6949 // be queried via setValue()
6950 // to set their value..
6951 (field.store && !field.store.isLocal)
6955 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6956 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6957 field.setFromData(sd);
6960 field.setValue(values[id]);
6964 if(this.trackResetOnLoad){
6965 field.originalValue = field.getValue();
6971 //Roo.each(this.childForms || [], function (f) {
6972 // f.setValues(values);
6979 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6980 * they are returned as an array.
6981 * @param {Boolean} asString
6984 getValues : function(asString){
6985 //if (this.childForms) {
6986 // copy values from the child forms
6987 // Roo.each(this.childForms, function (f) {
6988 // this.setValues(f.getValues());
6994 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6995 if(asString === true){
6998 return Roo.urlDecode(fs);
7002 * Returns the fields in this form as an object with key/value pairs.
7003 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7006 getFieldValues : function(with_hidden)
7008 var items = this.getItems();
7010 items.each(function(f){
7014 var v = f.getValue();
7015 if (f.inputType =='radio') {
7016 if (typeof(ret[f.getName()]) == 'undefined') {
7017 ret[f.getName()] = ''; // empty..
7020 if (!f.el.dom.checked) {
7028 // not sure if this supported any more..
7029 if ((typeof(v) == 'object') && f.getRawValue) {
7030 v = f.getRawValue() ; // dates..
7032 // combo boxes where name != hiddenName...
7033 if (f.name != f.getName()) {
7034 ret[f.name] = f.getRawValue();
7036 ret[f.getName()] = v;
7043 * Clears all invalid messages in this form.
7044 * @return {BasicForm} this
7046 clearInvalid : function(){
7047 var items = this.getItems();
7049 items.each(function(f){
7060 * @return {BasicForm} this
7063 var items = this.getItems();
7064 items.each(function(f){
7068 Roo.each(this.childForms || [], function (f) {
7075 getItems : function()
7077 var r=new Roo.util.MixedCollection(false, function(o){
7078 return o.id || (o.id = Roo.id());
7080 var iter = function(el) {
7087 Roo.each(el.items,function(e) {
7107 * Ext JS Library 1.1.1
7108 * Copyright(c) 2006-2007, Ext JS, LLC.
7110 * Originally Released Under LGPL - original licence link has changed is not relivant.
7113 * <script type="text/javascript">
7116 * @class Roo.form.VTypes
7117 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7120 Roo.form.VTypes = function(){
7121 // closure these in so they are only created once.
7122 var alpha = /^[a-zA-Z_]+$/;
7123 var alphanum = /^[a-zA-Z0-9_]+$/;
7124 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7125 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7127 // All these messages and functions are configurable
7130 * The function used to validate email addresses
7131 * @param {String} value The email address
7133 'email' : function(v){
7134 return email.test(v);
7137 * The error text to display when the email validation function returns false
7140 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7142 * The keystroke filter mask to be applied on email input
7145 'emailMask' : /[a-z0-9_\.\-@]/i,
7148 * The function used to validate URLs
7149 * @param {String} value The URL
7151 'url' : function(v){
7155 * The error text to display when the url validation function returns false
7158 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7161 * The function used to validate alpha values
7162 * @param {String} value The value
7164 'alpha' : function(v){
7165 return alpha.test(v);
7168 * The error text to display when the alpha validation function returns false
7171 'alphaText' : 'This field should only contain letters and _',
7173 * The keystroke filter mask to be applied on alpha input
7176 'alphaMask' : /[a-z_]/i,
7179 * The function used to validate alphanumeric values
7180 * @param {String} value The value
7182 'alphanum' : function(v){
7183 return alphanum.test(v);
7186 * The error text to display when the alphanumeric validation function returns false
7189 'alphanumText' : 'This field should only contain letters, numbers and _',
7191 * The keystroke filter mask to be applied on alphanumeric input
7194 'alphanumMask' : /[a-z0-9_]/i
7204 * @class Roo.bootstrap.Input
7205 * @extends Roo.bootstrap.Component
7206 * Bootstrap Input class
7207 * @cfg {Boolean} disabled is it disabled
7208 * @cfg {String} fieldLabel - the label associated
7209 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7210 * @cfg {String} name name of the input
7211 * @cfg {string} fieldLabel - the label associated
7212 * @cfg {string} inputType - input / file submit ...
7213 * @cfg {string} placeholder - placeholder to put in text.
7214 * @cfg {string} before - input group add on before
7215 * @cfg {string} after - input group add on after
7216 * @cfg {string} size - (lg|sm) or leave empty..
7217 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7218 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7219 * @cfg {Number} md colspan out of 12 for computer-sized screens
7220 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7221 * @cfg {string} value default value of the input
7222 * @cfg {Number} labelWidth set the width of label (0-12)
7223 * @cfg {String} labelAlign (top|left)
7224 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7225 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7227 * @cfg {String} align (left|center|right) Default left
7232 * Create a new Input
7233 * @param {Object} config The config object
7236 Roo.bootstrap.Input = function(config){
7237 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7242 * Fires when this field receives input focus.
7243 * @param {Roo.form.Field} this
7248 * Fires when this field loses input focus.
7249 * @param {Roo.form.Field} this
7254 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7255 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7256 * @param {Roo.form.Field} this
7257 * @param {Roo.EventObject} e The event object
7262 * Fires just before the field blurs if the field value has changed.
7263 * @param {Roo.form.Field} this
7264 * @param {Mixed} newValue The new value
7265 * @param {Mixed} oldValue The original value
7270 * Fires after the field has been marked as invalid.
7271 * @param {Roo.form.Field} this
7272 * @param {String} msg The validation message
7277 * Fires after the field has been validated with no errors.
7278 * @param {Roo.form.Field} this
7283 * Fires after the key up
7284 * @param {Roo.form.Field} this
7285 * @param {Roo.EventObject} e The event Object
7291 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7293 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7294 automatic validation (defaults to "keyup").
7296 validationEvent : "keyup",
7298 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7300 validateOnBlur : true,
7302 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7304 validationDelay : 250,
7306 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7308 focusClass : "x-form-focus", // not needed???
7312 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7314 invalidClass : "has-warning",
7317 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7319 validClass : "has-success",
7322 * @cfg {Boolean} hasFeedback (true|false) default true
7327 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7329 invalidFeedbackClass : "glyphicon-warning-sign",
7332 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7334 validFeedbackClass : "glyphicon-ok",
7337 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7339 selectOnFocus : false,
7342 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7346 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7351 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7353 disableKeyFilter : false,
7356 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7360 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7364 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7366 blankText : "This field is required",
7369 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7373 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7375 maxLength : Number.MAX_VALUE,
7377 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7379 minLengthText : "The minimum length for this field is {0}",
7381 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7383 maxLengthText : "The maximum length for this field is {0}",
7387 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7388 * If available, this function will be called only after the basic validators all return true, and will be passed the
7389 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7393 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7394 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7395 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7399 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7403 autocomplete: false,
7422 formatedValue : false,
7424 parentLabelAlign : function()
7427 while (parent.parent()) {
7428 parent = parent.parent();
7429 if (typeof(parent.labelAlign) !='undefined') {
7430 return parent.labelAlign;
7437 getAutoCreate : function(){
7439 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7445 if(this.inputType != 'hidden'){
7446 cfg.cls = 'form-group' //input-group
7452 type : this.inputType,
7454 cls : 'form-control',
7455 placeholder : this.placeholder || '',
7456 autocomplete : this.autocomplete || 'new-password'
7461 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7464 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7465 input.maxLength = this.maxLength;
7468 if (this.disabled) {
7469 input.disabled=true;
7472 if (this.readOnly) {
7473 input.readonly=true;
7477 input.name = this.name;
7480 input.cls += ' input-' + this.size;
7483 ['xs','sm','md','lg'].map(function(size){
7484 if (settings[size]) {
7485 cfg.cls += ' col-' + size + '-' + settings[size];
7489 var inputblock = input;
7493 cls: 'glyphicon form-control-feedback'
7496 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7499 cls : 'has-feedback',
7507 if (this.before || this.after) {
7510 cls : 'input-group',
7514 if (this.before && typeof(this.before) == 'string') {
7516 inputblock.cn.push({
7518 cls : 'roo-input-before input-group-addon',
7522 if (this.before && typeof(this.before) == 'object') {
7523 this.before = Roo.factory(this.before);
7524 Roo.log(this.before);
7525 inputblock.cn.push({
7527 cls : 'roo-input-before input-group-' +
7528 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7532 inputblock.cn.push(input);
7534 if (this.after && typeof(this.after) == 'string') {
7535 inputblock.cn.push({
7537 cls : 'roo-input-after input-group-addon',
7541 if (this.after && typeof(this.after) == 'object') {
7542 this.after = Roo.factory(this.after);
7543 Roo.log(this.after);
7544 inputblock.cn.push({
7546 cls : 'roo-input-after input-group-' +
7547 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7551 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7552 inputblock.cls += ' has-feedback';
7553 inputblock.cn.push(feedback);
7557 if (align ==='left' && this.fieldLabel.length) {
7558 Roo.log("left and has label");
7564 cls : 'control-label col-sm-' + this.labelWidth,
7565 html : this.fieldLabel
7569 cls : "col-sm-" + (12 - this.labelWidth),
7576 } else if ( this.fieldLabel.length) {
7582 //cls : 'input-group-addon',
7583 html : this.fieldLabel
7593 Roo.log(" no label && no align");
7602 Roo.log('input-parentType: ' + this.parentType);
7604 if (this.parentType === 'Navbar' && this.parent().bar) {
7605 cfg.cls += ' navbar-form';
7613 * return the real input element.
7615 inputEl: function ()
7617 return this.el.select('input.form-control',true).first();
7620 tooltipEl : function()
7622 return this.inputEl();
7625 setDisabled : function(v)
7627 var i = this.inputEl().dom;
7629 i.removeAttribute('disabled');
7633 i.setAttribute('disabled','true');
7635 initEvents : function()
7638 this.inputEl().on("keydown" , this.fireKey, this);
7639 this.inputEl().on("focus", this.onFocus, this);
7640 this.inputEl().on("blur", this.onBlur, this);
7642 this.inputEl().relayEvent('keyup', this);
7644 // reference to original value for reset
7645 this.originalValue = this.getValue();
7646 //Roo.form.TextField.superclass.initEvents.call(this);
7647 if(this.validationEvent == 'keyup'){
7648 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7649 this.inputEl().on('keyup', this.filterValidation, this);
7651 else if(this.validationEvent !== false){
7652 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7655 if(this.selectOnFocus){
7656 this.on("focus", this.preFocus, this);
7659 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7660 this.inputEl().on("keypress", this.filterKeys, this);
7663 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7664 this.el.on("click", this.autoSize, this);
7667 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7668 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7671 if (typeof(this.before) == 'object') {
7672 this.before.render(this.el.select('.roo-input-before',true).first());
7674 if (typeof(this.after) == 'object') {
7675 this.after.render(this.el.select('.roo-input-after',true).first());
7680 filterValidation : function(e){
7681 if(!e.isNavKeyPress()){
7682 this.validationTask.delay(this.validationDelay);
7686 * Validates the field value
7687 * @return {Boolean} True if the value is valid, else false
7689 validate : function(){
7690 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7691 if(this.disabled || this.validateValue(this.getRawValue())){
7702 * Validates a value according to the field's validation rules and marks the field as invalid
7703 * if the validation fails
7704 * @param {Mixed} value The value to validate
7705 * @return {Boolean} True if the value is valid, else false
7707 validateValue : function(value){
7708 if(value.length < 1) { // if it's blank
7709 if(this.allowBlank){
7715 if(value.length < this.minLength){
7718 if(value.length > this.maxLength){
7722 var vt = Roo.form.VTypes;
7723 if(!vt[this.vtype](value, this)){
7727 if(typeof this.validator == "function"){
7728 var msg = this.validator(value);
7734 if(this.regex && !this.regex.test(value)){
7744 fireKey : function(e){
7745 //Roo.log('field ' + e.getKey());
7746 if(e.isNavKeyPress()){
7747 this.fireEvent("specialkey", this, e);
7750 focus : function (selectText){
7752 this.inputEl().focus();
7753 if(selectText === true){
7754 this.inputEl().dom.select();
7760 onFocus : function(){
7761 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7762 // this.el.addClass(this.focusClass);
7765 this.hasFocus = true;
7766 this.startValue = this.getValue();
7767 this.fireEvent("focus", this);
7771 beforeBlur : Roo.emptyFn,
7775 onBlur : function(){
7777 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7778 //this.el.removeClass(this.focusClass);
7780 this.hasFocus = false;
7781 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7784 var v = this.getValue();
7785 if(String(v) !== String(this.startValue)){
7786 this.fireEvent('change', this, v, this.startValue);
7788 this.fireEvent("blur", this);
7792 * Resets the current field value to the originally loaded value and clears any validation messages
7795 this.setValue(this.originalValue);
7799 * Returns the name of the field
7800 * @return {Mixed} name The name field
7802 getName: function(){
7806 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7807 * @return {Mixed} value The field value
7809 getValue : function(){
7811 var v = this.inputEl().getValue();
7816 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7817 * @return {Mixed} value The field value
7819 getRawValue : function(){
7820 var v = this.inputEl().getValue();
7826 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7827 * @param {Mixed} value The value to set
7829 setRawValue : function(v){
7830 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7833 selectText : function(start, end){
7834 var v = this.getRawValue();
7836 start = start === undefined ? 0 : start;
7837 end = end === undefined ? v.length : end;
7838 var d = this.inputEl().dom;
7839 if(d.setSelectionRange){
7840 d.setSelectionRange(start, end);
7841 }else if(d.createTextRange){
7842 var range = d.createTextRange();
7843 range.moveStart("character", start);
7844 range.moveEnd("character", v.length-end);
7851 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7852 * @param {Mixed} value The value to set
7854 setValue : function(v){
7857 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7863 processValue : function(value){
7864 if(this.stripCharsRe){
7865 var newValue = value.replace(this.stripCharsRe, '');
7866 if(newValue !== value){
7867 this.setRawValue(newValue);
7874 preFocus : function(){
7876 if(this.selectOnFocus){
7877 this.inputEl().dom.select();
7880 filterKeys : function(e){
7882 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7885 var c = e.getCharCode(), cc = String.fromCharCode(c);
7886 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7889 if(!this.maskRe.test(cc)){
7894 * Clear any invalid styles/messages for this field
7896 clearInvalid : function(){
7898 if(!this.el || this.preventMark){ // not rendered
7901 this.el.removeClass(this.invalidClass);
7903 this.fireEvent('valid', this);
7907 * Mark this field as valid
7909 markValid : function(){
7910 if(!this.el || this.preventMark){ // not rendered
7914 this.el.removeClass([this.invalidClass, this.validClass]);
7916 if(this.disabled || this.allowBlank){
7920 this.el.addClass(this.validClass);
7922 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7924 var feedback = this.el.select('.form-control-feedback', true).first();
7927 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7928 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7933 this.fireEvent('valid', this);
7937 * Mark this field as invalid
7938 * @param {String} msg The validation message
7940 markInvalid : function(msg){
7941 if(!this.el || this.preventMark){ // not rendered
7945 this.el.removeClass([this.invalidClass, this.validClass]);
7947 if(this.disabled || this.allowBlank){
7951 this.el.addClass(this.invalidClass);
7953 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7955 var feedback = this.el.select('.form-control-feedback', true).first();
7958 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7960 if(this.getValue().length){
7961 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7968 this.fireEvent('invalid', this, msg);
7971 SafariOnKeyDown : function(event)
7973 // this is a workaround for a password hang bug on chrome/ webkit.
7975 var isSelectAll = false;
7977 if(this.inputEl().dom.selectionEnd > 0){
7978 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7980 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7981 event.preventDefault();
7986 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7988 event.preventDefault();
7989 // this is very hacky as keydown always get's upper case.
7991 var cc = String.fromCharCode(event.getCharCode());
7992 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7996 adjustWidth : function(tag, w){
7997 tag = tag.toLowerCase();
7998 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7999 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8003 if(tag == 'textarea'){
8006 }else if(Roo.isOpera){
8010 if(tag == 'textarea'){
8029 * @class Roo.bootstrap.TextArea
8030 * @extends Roo.bootstrap.Input
8031 * Bootstrap TextArea class
8032 * @cfg {Number} cols Specifies the visible width of a text area
8033 * @cfg {Number} rows Specifies the visible number of lines in a text area
8034 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8035 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8036 * @cfg {string} html text
8039 * Create a new TextArea
8040 * @param {Object} config The config object
8043 Roo.bootstrap.TextArea = function(config){
8044 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8048 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8058 getAutoCreate : function(){
8060 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8071 value : this.value || '',
8072 html: this.html || '',
8073 cls : 'form-control',
8074 placeholder : this.placeholder || ''
8078 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8079 input.maxLength = this.maxLength;
8083 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8087 input.cols = this.cols;
8090 if (this.readOnly) {
8091 input.readonly = true;
8095 input.name = this.name;
8099 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8103 ['xs','sm','md','lg'].map(function(size){
8104 if (settings[size]) {
8105 cfg.cls += ' col-' + size + '-' + settings[size];
8109 var inputblock = input;
8111 if(this.hasFeedback && !this.allowBlank){
8115 cls: 'glyphicon form-control-feedback'
8119 cls : 'has-feedback',
8128 if (this.before || this.after) {
8131 cls : 'input-group',
8135 inputblock.cn.push({
8137 cls : 'input-group-addon',
8142 inputblock.cn.push(input);
8144 if(this.hasFeedback && !this.allowBlank){
8145 inputblock.cls += ' has-feedback';
8146 inputblock.cn.push(feedback);
8150 inputblock.cn.push({
8152 cls : 'input-group-addon',
8159 if (align ==='left' && this.fieldLabel.length) {
8160 Roo.log("left and has label");
8166 cls : 'control-label col-sm-' + this.labelWidth,
8167 html : this.fieldLabel
8171 cls : "col-sm-" + (12 - this.labelWidth),
8178 } else if ( this.fieldLabel.length) {
8184 //cls : 'input-group-addon',
8185 html : this.fieldLabel
8195 Roo.log(" no label && no align");
8205 if (this.disabled) {
8206 input.disabled=true;
8213 * return the real textarea element.
8215 inputEl: function ()
8217 return this.el.select('textarea.form-control',true).first();
8225 * trigger field - base class for combo..
8230 * @class Roo.bootstrap.TriggerField
8231 * @extends Roo.bootstrap.Input
8232 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8233 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8234 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8235 * for which you can provide a custom implementation. For example:
8237 var trigger = new Roo.bootstrap.TriggerField();
8238 trigger.onTriggerClick = myTriggerFn;
8239 trigger.applyTo('my-field');
8242 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8243 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8244 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8245 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8246 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8249 * Create a new TriggerField.
8250 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8251 * to the base TextField)
8253 Roo.bootstrap.TriggerField = function(config){
8254 this.mimicing = false;
8255 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8258 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8260 * @cfg {String} triggerClass A CSS class to apply to the trigger
8263 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8267 /** @cfg {Boolean} grow @hide */
8268 /** @cfg {Number} growMin @hide */
8269 /** @cfg {Number} growMax @hide */
8275 autoSize: Roo.emptyFn,
8282 actionMode : 'wrap',
8287 getAutoCreate : function(){
8289 var align = this.labelAlign || this.parentLabelAlign();
8294 cls: 'form-group' //input-group
8301 type : this.inputType,
8302 cls : 'form-control',
8303 autocomplete: 'new-password',
8304 placeholder : this.placeholder || ''
8308 input.name = this.name;
8311 input.cls += ' input-' + this.size;
8314 if (this.disabled) {
8315 input.disabled=true;
8318 var inputblock = input;
8320 if(this.hasFeedback && !this.allowBlank){
8324 cls: 'glyphicon form-control-feedback'
8328 cls : 'has-feedback',
8336 if (this.before || this.after) {
8339 cls : 'input-group',
8343 inputblock.cn.push({
8345 cls : 'input-group-addon',
8350 inputblock.cn.push(input);
8352 if(this.hasFeedback && !this.allowBlank){
8353 inputblock.cls += ' has-feedback';
8354 inputblock.cn.push(feedback);
8358 inputblock.cn.push({
8360 cls : 'input-group-addon',
8373 cls: 'form-hidden-field'
8381 Roo.log('multiple');
8389 cls: 'form-hidden-field'
8393 cls: 'select2-choices',
8397 cls: 'select2-search-field',
8410 cls: 'select2-container input-group',
8415 // cls: 'typeahead typeahead-long dropdown-menu',
8416 // style: 'display:none'
8421 if(!this.multiple && this.showToggleBtn){
8427 if (this.caret != false) {
8430 cls: 'fa fa-' + this.caret
8437 cls : 'input-group-addon btn dropdown-toggle',
8442 cls: 'combobox-clear',
8456 combobox.cls += ' select2-container-multi';
8459 if (align ==='left' && this.fieldLabel.length) {
8461 Roo.log("left and has label");
8467 cls : 'control-label col-sm-' + this.labelWidth,
8468 html : this.fieldLabel
8472 cls : "col-sm-" + (12 - this.labelWidth),
8479 } else if ( this.fieldLabel.length) {
8485 //cls : 'input-group-addon',
8486 html : this.fieldLabel
8496 Roo.log(" no label && no align");
8503 ['xs','sm','md','lg'].map(function(size){
8504 if (settings[size]) {
8505 cfg.cls += ' col-' + size + '-' + settings[size];
8516 onResize : function(w, h){
8517 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8518 // if(typeof w == 'number'){
8519 // var x = w - this.trigger.getWidth();
8520 // this.inputEl().setWidth(this.adjustWidth('input', x));
8521 // this.trigger.setStyle('left', x+'px');
8526 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8529 getResizeEl : function(){
8530 return this.inputEl();
8534 getPositionEl : function(){
8535 return this.inputEl();
8539 alignErrorIcon : function(){
8540 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8544 initEvents : function(){
8548 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8549 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8550 if(!this.multiple && this.showToggleBtn){
8551 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8552 if(this.hideTrigger){
8553 this.trigger.setDisplayed(false);
8555 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8559 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8562 //this.trigger.addClassOnOver('x-form-trigger-over');
8563 //this.trigger.addClassOnClick('x-form-trigger-click');
8566 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8570 createList : function()
8572 this.list = Roo.get(document.body).createChild({
8574 cls: 'typeahead typeahead-long dropdown-menu',
8575 style: 'display:none'
8578 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8583 initTrigger : function(){
8588 onDestroy : function(){
8590 this.trigger.removeAllListeners();
8591 // this.trigger.remove();
8594 // this.wrap.remove();
8596 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8600 onFocus : function(){
8601 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8604 this.wrap.addClass('x-trigger-wrap-focus');
8605 this.mimicing = true;
8606 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8607 if(this.monitorTab){
8608 this.el.on("keydown", this.checkTab, this);
8615 checkTab : function(e){
8616 if(e.getKey() == e.TAB){
8622 onBlur : function(){
8627 mimicBlur : function(e, t){
8629 if(!this.wrap.contains(t) && this.validateBlur()){
8636 triggerBlur : function(){
8637 this.mimicing = false;
8638 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8639 if(this.monitorTab){
8640 this.el.un("keydown", this.checkTab, this);
8642 //this.wrap.removeClass('x-trigger-wrap-focus');
8643 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8647 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8648 validateBlur : function(e, t){
8653 onDisable : function(){
8654 this.inputEl().dom.disabled = true;
8655 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8657 // this.wrap.addClass('x-item-disabled');
8662 onEnable : function(){
8663 this.inputEl().dom.disabled = false;
8664 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8666 // this.el.removeClass('x-item-disabled');
8671 onShow : function(){
8672 var ae = this.getActionEl();
8675 ae.dom.style.display = '';
8676 ae.dom.style.visibility = 'visible';
8682 onHide : function(){
8683 var ae = this.getActionEl();
8684 ae.dom.style.display = 'none';
8688 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8689 * by an implementing function.
8691 * @param {EventObject} e
8693 onTriggerClick : Roo.emptyFn
8697 * Ext JS Library 1.1.1
8698 * Copyright(c) 2006-2007, Ext JS, LLC.
8700 * Originally Released Under LGPL - original licence link has changed is not relivant.
8703 * <script type="text/javascript">
8708 * @class Roo.data.SortTypes
8710 * Defines the default sorting (casting?) comparison functions used when sorting data.
8712 Roo.data.SortTypes = {
8714 * Default sort that does nothing
8715 * @param {Mixed} s The value being converted
8716 * @return {Mixed} The comparison value
8723 * The regular expression used to strip tags
8727 stripTagsRE : /<\/?[^>]+>/gi,
8730 * Strips all HTML tags to sort on text only
8731 * @param {Mixed} s The value being converted
8732 * @return {String} The comparison value
8734 asText : function(s){
8735 return String(s).replace(this.stripTagsRE, "");
8739 * Strips all HTML tags to sort on text only - Case insensitive
8740 * @param {Mixed} s The value being converted
8741 * @return {String} The comparison value
8743 asUCText : function(s){
8744 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8748 * Case insensitive string
8749 * @param {Mixed} s The value being converted
8750 * @return {String} The comparison value
8752 asUCString : function(s) {
8753 return String(s).toUpperCase();
8758 * @param {Mixed} s The value being converted
8759 * @return {Number} The comparison value
8761 asDate : function(s) {
8765 if(s instanceof Date){
8768 return Date.parse(String(s));
8773 * @param {Mixed} s The value being converted
8774 * @return {Float} The comparison value
8776 asFloat : function(s) {
8777 var val = parseFloat(String(s).replace(/,/g, ""));
8778 if(isNaN(val)) val = 0;
8784 * @param {Mixed} s The value being converted
8785 * @return {Number} The comparison value
8787 asInt : function(s) {
8788 var val = parseInt(String(s).replace(/,/g, ""));
8789 if(isNaN(val)) val = 0;
8794 * Ext JS Library 1.1.1
8795 * Copyright(c) 2006-2007, Ext JS, LLC.
8797 * Originally Released Under LGPL - original licence link has changed is not relivant.
8800 * <script type="text/javascript">
8804 * @class Roo.data.Record
8805 * Instances of this class encapsulate both record <em>definition</em> information, and record
8806 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8807 * to access Records cached in an {@link Roo.data.Store} object.<br>
8809 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8810 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8813 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8815 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8816 * {@link #create}. The parameters are the same.
8817 * @param {Array} data An associative Array of data values keyed by the field name.
8818 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8819 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8820 * not specified an integer id is generated.
8822 Roo.data.Record = function(data, id){
8823 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8828 * Generate a constructor for a specific record layout.
8829 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8830 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8831 * Each field definition object may contain the following properties: <ul>
8832 * <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,
8833 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8834 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8835 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8836 * is being used, then this is a string containing the javascript expression to reference the data relative to
8837 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8838 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8839 * this may be omitted.</p></li>
8840 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8841 * <ul><li>auto (Default, implies no conversion)</li>
8846 * <li>date</li></ul></p></li>
8847 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8848 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8849 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8850 * by the Reader into an object that will be stored in the Record. It is passed the
8851 * following parameters:<ul>
8852 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8854 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8856 * <br>usage:<br><pre><code>
8857 var TopicRecord = Roo.data.Record.create(
8858 {name: 'title', mapping: 'topic_title'},
8859 {name: 'author', mapping: 'username'},
8860 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8861 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8862 {name: 'lastPoster', mapping: 'user2'},
8863 {name: 'excerpt', mapping: 'post_text'}
8866 var myNewRecord = new TopicRecord({
8867 title: 'Do my job please',
8870 lastPost: new Date(),
8871 lastPoster: 'Animal',
8872 excerpt: 'No way dude!'
8874 myStore.add(myNewRecord);
8879 Roo.data.Record.create = function(o){
8881 f.superclass.constructor.apply(this, arguments);
8883 Roo.extend(f, Roo.data.Record);
8884 var p = f.prototype;
8885 p.fields = new Roo.util.MixedCollection(false, function(field){
8888 for(var i = 0, len = o.length; i < len; i++){
8889 p.fields.add(new Roo.data.Field(o[i]));
8891 f.getField = function(name){
8892 return p.fields.get(name);
8897 Roo.data.Record.AUTO_ID = 1000;
8898 Roo.data.Record.EDIT = 'edit';
8899 Roo.data.Record.REJECT = 'reject';
8900 Roo.data.Record.COMMIT = 'commit';
8902 Roo.data.Record.prototype = {
8904 * Readonly flag - true if this record has been modified.
8913 join : function(store){
8918 * Set the named field to the specified value.
8919 * @param {String} name The name of the field to set.
8920 * @param {Object} value The value to set the field to.
8922 set : function(name, value){
8923 if(this.data[name] == value){
8930 if(typeof this.modified[name] == 'undefined'){
8931 this.modified[name] = this.data[name];
8933 this.data[name] = value;
8934 if(!this.editing && this.store){
8935 this.store.afterEdit(this);
8940 * Get the value of the named field.
8941 * @param {String} name The name of the field to get the value of.
8942 * @return {Object} The value of the field.
8944 get : function(name){
8945 return this.data[name];
8949 beginEdit : function(){
8950 this.editing = true;
8955 cancelEdit : function(){
8956 this.editing = false;
8957 delete this.modified;
8961 endEdit : function(){
8962 this.editing = false;
8963 if(this.dirty && this.store){
8964 this.store.afterEdit(this);
8969 * Usually called by the {@link Roo.data.Store} which owns the Record.
8970 * Rejects all changes made to the Record since either creation, or the last commit operation.
8971 * Modified fields are reverted to their original values.
8973 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8974 * of reject operations.
8976 reject : function(){
8977 var m = this.modified;
8979 if(typeof m[n] != "function"){
8980 this.data[n] = m[n];
8984 delete this.modified;
8985 this.editing = false;
8987 this.store.afterReject(this);
8992 * Usually called by the {@link Roo.data.Store} which owns the Record.
8993 * Commits all changes made to the Record since either creation, or the last commit operation.
8995 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8996 * of commit operations.
8998 commit : function(){
9000 delete this.modified;
9001 this.editing = false;
9003 this.store.afterCommit(this);
9008 hasError : function(){
9009 return this.error != null;
9013 clearError : function(){
9018 * Creates a copy of this record.
9019 * @param {String} id (optional) A new record id if you don't want to use this record's id
9022 copy : function(newId) {
9023 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9027 * Ext JS Library 1.1.1
9028 * Copyright(c) 2006-2007, Ext JS, LLC.
9030 * Originally Released Under LGPL - original licence link has changed is not relivant.
9033 * <script type="text/javascript">
9039 * @class Roo.data.Store
9040 * @extends Roo.util.Observable
9041 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9042 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9044 * 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
9045 * has no knowledge of the format of the data returned by the Proxy.<br>
9047 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9048 * instances from the data object. These records are cached and made available through accessor functions.
9050 * Creates a new Store.
9051 * @param {Object} config A config object containing the objects needed for the Store to access data,
9052 * and read the data into Records.
9054 Roo.data.Store = function(config){
9055 this.data = new Roo.util.MixedCollection(false);
9056 this.data.getKey = function(o){
9059 this.baseParams = {};
9066 "multisort" : "_multisort"
9069 if(config && config.data){
9070 this.inlineData = config.data;
9074 Roo.apply(this, config);
9076 if(this.reader){ // reader passed
9077 this.reader = Roo.factory(this.reader, Roo.data);
9078 this.reader.xmodule = this.xmodule || false;
9079 if(!this.recordType){
9080 this.recordType = this.reader.recordType;
9082 if(this.reader.onMetaChange){
9083 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9087 if(this.recordType){
9088 this.fields = this.recordType.prototype.fields;
9094 * @event datachanged
9095 * Fires when the data cache has changed, and a widget which is using this Store
9096 * as a Record cache should refresh its view.
9097 * @param {Store} this
9102 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9103 * @param {Store} this
9104 * @param {Object} meta The JSON metadata
9109 * Fires when Records have been added to the Store
9110 * @param {Store} this
9111 * @param {Roo.data.Record[]} records The array of Records added
9112 * @param {Number} index The index at which the record(s) were added
9117 * Fires when a Record has been removed from the Store
9118 * @param {Store} this
9119 * @param {Roo.data.Record} record The Record that was removed
9120 * @param {Number} index The index at which the record was removed
9125 * Fires when a Record has been updated
9126 * @param {Store} this
9127 * @param {Roo.data.Record} record The Record that was updated
9128 * @param {String} operation The update operation being performed. Value may be one of:
9130 Roo.data.Record.EDIT
9131 Roo.data.Record.REJECT
9132 Roo.data.Record.COMMIT
9138 * Fires when the data cache has been cleared.
9139 * @param {Store} this
9144 * Fires before a request is made for a new data object. If the beforeload handler returns false
9145 * the load action will be canceled.
9146 * @param {Store} this
9147 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9151 * @event beforeloadadd
9152 * Fires after a new set of Records has been loaded.
9153 * @param {Store} this
9154 * @param {Roo.data.Record[]} records The Records that were loaded
9155 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9157 beforeloadadd : true,
9160 * Fires after a new set of Records has been loaded, before they are added to the store.
9161 * @param {Store} this
9162 * @param {Roo.data.Record[]} records The Records that were loaded
9163 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9164 * @params {Object} return from reader
9168 * @event loadexception
9169 * Fires if an exception occurs in the Proxy during loading.
9170 * Called with the signature of the Proxy's "loadexception" event.
9171 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9174 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9175 * @param {Object} load options
9176 * @param {Object} jsonData from your request (normally this contains the Exception)
9178 loadexception : true
9182 this.proxy = Roo.factory(this.proxy, Roo.data);
9183 this.proxy.xmodule = this.xmodule || false;
9184 this.relayEvents(this.proxy, ["loadexception"]);
9186 this.sortToggle = {};
9187 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9189 Roo.data.Store.superclass.constructor.call(this);
9191 if(this.inlineData){
9192 this.loadData(this.inlineData);
9193 delete this.inlineData;
9197 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9199 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9200 * without a remote query - used by combo/forms at present.
9204 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9207 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9210 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9211 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9214 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9215 * on any HTTP request
9218 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9221 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9225 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9226 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9231 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9232 * loaded or when a record is removed. (defaults to false).
9234 pruneModifiedRecords : false,
9240 * Add Records to the Store and fires the add event.
9241 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9243 add : function(records){
9244 records = [].concat(records);
9245 for(var i = 0, len = records.length; i < len; i++){
9246 records[i].join(this);
9248 var index = this.data.length;
9249 this.data.addAll(records);
9250 this.fireEvent("add", this, records, index);
9254 * Remove a Record from the Store and fires the remove event.
9255 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9257 remove : function(record){
9258 var index = this.data.indexOf(record);
9259 this.data.removeAt(index);
9260 if(this.pruneModifiedRecords){
9261 this.modified.remove(record);
9263 this.fireEvent("remove", this, record, index);
9267 * Remove all Records from the Store and fires the clear event.
9269 removeAll : function(){
9271 if(this.pruneModifiedRecords){
9274 this.fireEvent("clear", this);
9278 * Inserts Records to the Store at the given index and fires the add event.
9279 * @param {Number} index The start index at which to insert the passed Records.
9280 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9282 insert : function(index, records){
9283 records = [].concat(records);
9284 for(var i = 0, len = records.length; i < len; i++){
9285 this.data.insert(index, records[i]);
9286 records[i].join(this);
9288 this.fireEvent("add", this, records, index);
9292 * Get the index within the cache of the passed Record.
9293 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9294 * @return {Number} The index of the passed Record. Returns -1 if not found.
9296 indexOf : function(record){
9297 return this.data.indexOf(record);
9301 * Get the index within the cache of the Record with the passed id.
9302 * @param {String} id The id of the Record to find.
9303 * @return {Number} The index of the Record. Returns -1 if not found.
9305 indexOfId : function(id){
9306 return this.data.indexOfKey(id);
9310 * Get the Record with the specified id.
9311 * @param {String} id The id of the Record to find.
9312 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9314 getById : function(id){
9315 return this.data.key(id);
9319 * Get the Record at the specified index.
9320 * @param {Number} index The index of the Record to find.
9321 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9323 getAt : function(index){
9324 return this.data.itemAt(index);
9328 * Returns a range of Records between specified indices.
9329 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9330 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9331 * @return {Roo.data.Record[]} An array of Records
9333 getRange : function(start, end){
9334 return this.data.getRange(start, end);
9338 storeOptions : function(o){
9339 o = Roo.apply({}, o);
9342 this.lastOptions = o;
9346 * Loads the Record cache from the configured Proxy using the configured Reader.
9348 * If using remote paging, then the first load call must specify the <em>start</em>
9349 * and <em>limit</em> properties in the options.params property to establish the initial
9350 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9352 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9353 * and this call will return before the new data has been loaded. Perform any post-processing
9354 * in a callback function, or in a "load" event handler.</strong>
9356 * @param {Object} options An object containing properties which control loading options:<ul>
9357 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9358 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9359 * passed the following arguments:<ul>
9360 * <li>r : Roo.data.Record[]</li>
9361 * <li>options: Options object from the load call</li>
9362 * <li>success: Boolean success indicator</li></ul></li>
9363 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9364 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9367 load : function(options){
9368 options = options || {};
9369 if(this.fireEvent("beforeload", this, options) !== false){
9370 this.storeOptions(options);
9371 var p = Roo.apply(options.params || {}, this.baseParams);
9372 // if meta was not loaded from remote source.. try requesting it.
9373 if (!this.reader.metaFromRemote) {
9376 if(this.sortInfo && this.remoteSort){
9377 var pn = this.paramNames;
9378 p[pn["sort"]] = this.sortInfo.field;
9379 p[pn["dir"]] = this.sortInfo.direction;
9381 if (this.multiSort) {
9382 var pn = this.paramNames;
9383 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9386 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9391 * Reloads the Record cache from the configured Proxy using the configured Reader and
9392 * the options from the last load operation performed.
9393 * @param {Object} options (optional) An object containing properties which may override the options
9394 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9395 * the most recently used options are reused).
9397 reload : function(options){
9398 this.load(Roo.applyIf(options||{}, this.lastOptions));
9402 // Called as a callback by the Reader during a load operation.
9403 loadRecords : function(o, options, success){
9404 if(!o || success === false){
9405 if(success !== false){
9406 this.fireEvent("load", this, [], options, o);
9408 if(options.callback){
9409 options.callback.call(options.scope || this, [], options, false);
9413 // if data returned failure - throw an exception.
9414 if (o.success === false) {
9415 // show a message if no listener is registered.
9416 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9417 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9419 // loadmask wil be hooked into this..
9420 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9423 var r = o.records, t = o.totalRecords || r.length;
9425 this.fireEvent("beforeloadadd", this, r, options, o);
9427 if(!options || options.add !== true){
9428 if(this.pruneModifiedRecords){
9431 for(var i = 0, len = r.length; i < len; i++){
9435 this.data = this.snapshot;
9436 delete this.snapshot;
9439 this.data.addAll(r);
9440 this.totalLength = t;
9442 this.fireEvent("datachanged", this);
9444 this.totalLength = Math.max(t, this.data.length+r.length);
9447 this.fireEvent("load", this, r, options, o);
9448 if(options.callback){
9449 options.callback.call(options.scope || this, r, options, true);
9455 * Loads data from a passed data block. A Reader which understands the format of the data
9456 * must have been configured in the constructor.
9457 * @param {Object} data The data block from which to read the Records. The format of the data expected
9458 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9459 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9461 loadData : function(o, append){
9462 var r = this.reader.readRecords(o);
9463 this.loadRecords(r, {add: append}, true);
9467 * Gets the number of cached records.
9469 * <em>If using paging, this may not be the total size of the dataset. If the data object
9470 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9471 * the data set size</em>
9473 getCount : function(){
9474 return this.data.length || 0;
9478 * Gets the total number of records in the dataset as returned by the server.
9480 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9481 * the dataset size</em>
9483 getTotalCount : function(){
9484 return this.totalLength || 0;
9488 * Returns the sort state of the Store as an object with two properties:
9490 field {String} The name of the field by which the Records are sorted
9491 direction {String} The sort order, "ASC" or "DESC"
9494 getSortState : function(){
9495 return this.sortInfo;
9499 applySort : function(){
9500 if(this.sortInfo && !this.remoteSort){
9501 var s = this.sortInfo, f = s.field;
9502 var st = this.fields.get(f).sortType;
9503 var fn = function(r1, r2){
9504 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9505 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9507 this.data.sort(s.direction, fn);
9508 if(this.snapshot && this.snapshot != this.data){
9509 this.snapshot.sort(s.direction, fn);
9515 * Sets the default sort column and order to be used by the next load operation.
9516 * @param {String} fieldName The name of the field to sort by.
9517 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9519 setDefaultSort : function(field, dir){
9520 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9525 * If remote sorting is used, the sort is performed on the server, and the cache is
9526 * reloaded. If local sorting is used, the cache is sorted internally.
9527 * @param {String} fieldName The name of the field to sort by.
9528 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9530 sort : function(fieldName, dir){
9531 var f = this.fields.get(fieldName);
9533 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9535 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9536 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9541 this.sortToggle[f.name] = dir;
9542 this.sortInfo = {field: f.name, direction: dir};
9543 if(!this.remoteSort){
9545 this.fireEvent("datachanged", this);
9547 this.load(this.lastOptions);
9552 * Calls the specified function for each of the Records in the cache.
9553 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9554 * Returning <em>false</em> aborts and exits the iteration.
9555 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9557 each : function(fn, scope){
9558 this.data.each(fn, scope);
9562 * Gets all records modified since the last commit. Modified records are persisted across load operations
9563 * (e.g., during paging).
9564 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9566 getModifiedRecords : function(){
9567 return this.modified;
9571 createFilterFn : function(property, value, anyMatch){
9572 if(!value.exec){ // not a regex
9573 value = String(value);
9574 if(value.length == 0){
9577 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9580 return value.test(r.data[property]);
9585 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9586 * @param {String} property A field on your records
9587 * @param {Number} start The record index to start at (defaults to 0)
9588 * @param {Number} end The last record index to include (defaults to length - 1)
9589 * @return {Number} The sum
9591 sum : function(property, start, end){
9592 var rs = this.data.items, v = 0;
9594 end = (end || end === 0) ? end : rs.length-1;
9596 for(var i = start; i <= end; i++){
9597 v += (rs[i].data[property] || 0);
9603 * Filter the records by a specified property.
9604 * @param {String} field A field on your records
9605 * @param {String/RegExp} value Either a string that the field
9606 * should start with or a RegExp to test against the field
9607 * @param {Boolean} anyMatch True to match any part not just the beginning
9609 filter : function(property, value, anyMatch){
9610 var fn = this.createFilterFn(property, value, anyMatch);
9611 return fn ? this.filterBy(fn) : this.clearFilter();
9615 * Filter by a function. The specified function will be called with each
9616 * record in this data source. If the function returns true the record is included,
9617 * otherwise it is filtered.
9618 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9619 * @param {Object} scope (optional) The scope of the function (defaults to this)
9621 filterBy : function(fn, scope){
9622 this.snapshot = this.snapshot || this.data;
9623 this.data = this.queryBy(fn, scope||this);
9624 this.fireEvent("datachanged", this);
9628 * Query the records by a specified property.
9629 * @param {String} field A field on your records
9630 * @param {String/RegExp} value Either a string that the field
9631 * should start with or a RegExp to test against the field
9632 * @param {Boolean} anyMatch True to match any part not just the beginning
9633 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9635 query : function(property, value, anyMatch){
9636 var fn = this.createFilterFn(property, value, anyMatch);
9637 return fn ? this.queryBy(fn) : this.data.clone();
9641 * Query by a function. The specified function will be called with each
9642 * record in this data source. If the function returns true the record is included
9644 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9645 * @param {Object} scope (optional) The scope of the function (defaults to this)
9646 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9648 queryBy : function(fn, scope){
9649 var data = this.snapshot || this.data;
9650 return data.filterBy(fn, scope||this);
9654 * Collects unique values for a particular dataIndex from this store.
9655 * @param {String} dataIndex The property to collect
9656 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9657 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9658 * @return {Array} An array of the unique values
9660 collect : function(dataIndex, allowNull, bypassFilter){
9661 var d = (bypassFilter === true && this.snapshot) ?
9662 this.snapshot.items : this.data.items;
9663 var v, sv, r = [], l = {};
9664 for(var i = 0, len = d.length; i < len; i++){
9665 v = d[i].data[dataIndex];
9667 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9676 * Revert to a view of the Record cache with no filtering applied.
9677 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9679 clearFilter : function(suppressEvent){
9680 if(this.snapshot && this.snapshot != this.data){
9681 this.data = this.snapshot;
9682 delete this.snapshot;
9683 if(suppressEvent !== true){
9684 this.fireEvent("datachanged", this);
9690 afterEdit : function(record){
9691 if(this.modified.indexOf(record) == -1){
9692 this.modified.push(record);
9694 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9698 afterReject : function(record){
9699 this.modified.remove(record);
9700 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9704 afterCommit : function(record){
9705 this.modified.remove(record);
9706 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9710 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9711 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9713 commitChanges : function(){
9714 var m = this.modified.slice(0);
9716 for(var i = 0, len = m.length; i < len; i++){
9722 * Cancel outstanding changes on all changed records.
9724 rejectChanges : function(){
9725 var m = this.modified.slice(0);
9727 for(var i = 0, len = m.length; i < len; i++){
9732 onMetaChange : function(meta, rtype, o){
9733 this.recordType = rtype;
9734 this.fields = rtype.prototype.fields;
9735 delete this.snapshot;
9736 this.sortInfo = meta.sortInfo || this.sortInfo;
9738 this.fireEvent('metachange', this, this.reader.meta);
9741 moveIndex : function(data, type)
9743 var index = this.indexOf(data);
9745 var newIndex = index + type;
9749 this.insert(newIndex, data);
9754 * Ext JS Library 1.1.1
9755 * Copyright(c) 2006-2007, Ext JS, LLC.
9757 * Originally Released Under LGPL - original licence link has changed is not relivant.
9760 * <script type="text/javascript">
9764 * @class Roo.data.SimpleStore
9765 * @extends Roo.data.Store
9766 * Small helper class to make creating Stores from Array data easier.
9767 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9768 * @cfg {Array} fields An array of field definition objects, or field name strings.
9769 * @cfg {Array} data The multi-dimensional array of data
9771 * @param {Object} config
9773 Roo.data.SimpleStore = function(config){
9774 Roo.data.SimpleStore.superclass.constructor.call(this, {
9776 reader: new Roo.data.ArrayReader({
9779 Roo.data.Record.create(config.fields)
9781 proxy : new Roo.data.MemoryProxy(config.data)
9785 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9787 * Ext JS Library 1.1.1
9788 * Copyright(c) 2006-2007, Ext JS, LLC.
9790 * Originally Released Under LGPL - original licence link has changed is not relivant.
9793 * <script type="text/javascript">
9798 * @extends Roo.data.Store
9799 * @class Roo.data.JsonStore
9800 * Small helper class to make creating Stores for JSON data easier. <br/>
9802 var store = new Roo.data.JsonStore({
9803 url: 'get-images.php',
9805 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9808 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9809 * JsonReader and HttpProxy (unless inline data is provided).</b>
9810 * @cfg {Array} fields An array of field definition objects, or field name strings.
9812 * @param {Object} config
9814 Roo.data.JsonStore = function(c){
9815 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9816 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9817 reader: new Roo.data.JsonReader(c, c.fields)
9820 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9822 * Ext JS Library 1.1.1
9823 * Copyright(c) 2006-2007, Ext JS, LLC.
9825 * Originally Released Under LGPL - original licence link has changed is not relivant.
9828 * <script type="text/javascript">
9832 Roo.data.Field = function(config){
9833 if(typeof config == "string"){
9834 config = {name: config};
9836 Roo.apply(this, config);
9842 var st = Roo.data.SortTypes;
9843 // named sortTypes are supported, here we look them up
9844 if(typeof this.sortType == "string"){
9845 this.sortType = st[this.sortType];
9848 // set default sortType for strings and dates
9852 this.sortType = st.asUCString;
9855 this.sortType = st.asDate;
9858 this.sortType = st.none;
9863 var stripRe = /[\$,%]/g;
9865 // prebuilt conversion function for this field, instead of
9866 // switching every time we're reading a value
9868 var cv, dateFormat = this.dateFormat;
9873 cv = function(v){ return v; };
9876 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9880 return v !== undefined && v !== null && v !== '' ?
9881 parseInt(String(v).replace(stripRe, ""), 10) : '';
9886 return v !== undefined && v !== null && v !== '' ?
9887 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9892 cv = function(v){ return v === true || v === "true" || v == 1; };
9899 if(v instanceof Date){
9903 if(dateFormat == "timestamp"){
9904 return new Date(v*1000);
9906 return Date.parseDate(v, dateFormat);
9908 var parsed = Date.parse(v);
9909 return parsed ? new Date(parsed) : null;
9918 Roo.data.Field.prototype = {
9926 * Ext JS Library 1.1.1
9927 * Copyright(c) 2006-2007, Ext JS, LLC.
9929 * Originally Released Under LGPL - original licence link has changed is not relivant.
9932 * <script type="text/javascript">
9935 // Base class for reading structured data from a data source. This class is intended to be
9936 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9939 * @class Roo.data.DataReader
9940 * Base class for reading structured data from a data source. This class is intended to be
9941 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9944 Roo.data.DataReader = function(meta, recordType){
9948 this.recordType = recordType instanceof Array ?
9949 Roo.data.Record.create(recordType) : recordType;
9952 Roo.data.DataReader.prototype = {
9954 * Create an empty record
9955 * @param {Object} data (optional) - overlay some values
9956 * @return {Roo.data.Record} record created.
9958 newRow : function(d) {
9960 this.recordType.prototype.fields.each(function(c) {
9962 case 'int' : da[c.name] = 0; break;
9963 case 'date' : da[c.name] = new Date(); break;
9964 case 'float' : da[c.name] = 0.0; break;
9965 case 'boolean' : da[c.name] = false; break;
9966 default : da[c.name] = ""; break;
9970 return new this.recordType(Roo.apply(da, d));
9975 * Ext JS Library 1.1.1
9976 * Copyright(c) 2006-2007, Ext JS, LLC.
9978 * Originally Released Under LGPL - original licence link has changed is not relivant.
9981 * <script type="text/javascript">
9985 * @class Roo.data.DataProxy
9986 * @extends Roo.data.Observable
9987 * This class is an abstract base class for implementations which provide retrieval of
9988 * unformatted data objects.<br>
9990 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9991 * (of the appropriate type which knows how to parse the data object) to provide a block of
9992 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9994 * Custom implementations must implement the load method as described in
9995 * {@link Roo.data.HttpProxy#load}.
9997 Roo.data.DataProxy = function(){
10000 * @event beforeload
10001 * Fires before a network request is made to retrieve a data object.
10002 * @param {Object} This DataProxy object.
10003 * @param {Object} params The params parameter to the load function.
10008 * Fires before the load method's callback is called.
10009 * @param {Object} This DataProxy object.
10010 * @param {Object} o The data object.
10011 * @param {Object} arg The callback argument object passed to the load function.
10015 * @event loadexception
10016 * Fires if an Exception occurs during data retrieval.
10017 * @param {Object} This DataProxy object.
10018 * @param {Object} o The data object.
10019 * @param {Object} arg The callback argument object passed to the load function.
10020 * @param {Object} e The Exception.
10022 loadexception : true
10024 Roo.data.DataProxy.superclass.constructor.call(this);
10027 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10030 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10034 * Ext JS Library 1.1.1
10035 * Copyright(c) 2006-2007, Ext JS, LLC.
10037 * Originally Released Under LGPL - original licence link has changed is not relivant.
10040 * <script type="text/javascript">
10043 * @class Roo.data.MemoryProxy
10044 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10045 * to the Reader when its load method is called.
10047 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10049 Roo.data.MemoryProxy = function(data){
10053 Roo.data.MemoryProxy.superclass.constructor.call(this);
10057 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10059 * Load data from the requested source (in this case an in-memory
10060 * data object passed to the constructor), read the data object into
10061 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10062 * process that block using the passed callback.
10063 * @param {Object} params This parameter is not used by the MemoryProxy class.
10064 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10065 * object into a block of Roo.data.Records.
10066 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10067 * The function must be passed <ul>
10068 * <li>The Record block object</li>
10069 * <li>The "arg" argument from the load function</li>
10070 * <li>A boolean success indicator</li>
10072 * @param {Object} scope The scope in which to call the callback
10073 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10075 load : function(params, reader, callback, scope, arg){
10076 params = params || {};
10079 result = reader.readRecords(this.data);
10081 this.fireEvent("loadexception", this, arg, null, e);
10082 callback.call(scope, null, arg, false);
10085 callback.call(scope, result, arg, true);
10089 update : function(params, records){
10094 * Ext JS Library 1.1.1
10095 * Copyright(c) 2006-2007, Ext JS, LLC.
10097 * Originally Released Under LGPL - original licence link has changed is not relivant.
10100 * <script type="text/javascript">
10103 * @class Roo.data.HttpProxy
10104 * @extends Roo.data.DataProxy
10105 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10106 * configured to reference a certain URL.<br><br>
10108 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10109 * from which the running page was served.<br><br>
10111 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10113 * Be aware that to enable the browser to parse an XML document, the server must set
10114 * the Content-Type header in the HTTP response to "text/xml".
10116 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10117 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10118 * will be used to make the request.
10120 Roo.data.HttpProxy = function(conn){
10121 Roo.data.HttpProxy.superclass.constructor.call(this);
10122 // is conn a conn config or a real conn?
10124 this.useAjax = !conn || !conn.events;
10128 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10129 // thse are take from connection...
10132 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10135 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10136 * extra parameters to each request made by this object. (defaults to undefined)
10139 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10140 * to each request made by this object. (defaults to undefined)
10143 * @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)
10146 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10149 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10155 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10159 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10160 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10161 * a finer-grained basis than the DataProxy events.
10163 getConnection : function(){
10164 return this.useAjax ? Roo.Ajax : this.conn;
10168 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10169 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10170 * process that block using the passed callback.
10171 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10172 * for the request to the remote server.
10173 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10174 * object into a block of Roo.data.Records.
10175 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10176 * The function must be passed <ul>
10177 * <li>The Record block object</li>
10178 * <li>The "arg" argument from the load function</li>
10179 * <li>A boolean success indicator</li>
10181 * @param {Object} scope The scope in which to call the callback
10182 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10184 load : function(params, reader, callback, scope, arg){
10185 if(this.fireEvent("beforeload", this, params) !== false){
10187 params : params || {},
10189 callback : callback,
10194 callback : this.loadResponse,
10198 Roo.applyIf(o, this.conn);
10199 if(this.activeRequest){
10200 Roo.Ajax.abort(this.activeRequest);
10202 this.activeRequest = Roo.Ajax.request(o);
10204 this.conn.request(o);
10207 callback.call(scope||this, null, arg, false);
10212 loadResponse : function(o, success, response){
10213 delete this.activeRequest;
10215 this.fireEvent("loadexception", this, o, response);
10216 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10221 result = o.reader.read(response);
10223 this.fireEvent("loadexception", this, o, response, e);
10224 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10228 this.fireEvent("load", this, o, o.request.arg);
10229 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10233 update : function(dataSet){
10238 updateResponse : function(dataSet){
10243 * Ext JS Library 1.1.1
10244 * Copyright(c) 2006-2007, Ext JS, LLC.
10246 * Originally Released Under LGPL - original licence link has changed is not relivant.
10249 * <script type="text/javascript">
10253 * @class Roo.data.ScriptTagProxy
10254 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10255 * other than the originating domain of the running page.<br><br>
10257 * <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
10258 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10260 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10261 * source code that is used as the source inside a <script> tag.<br><br>
10263 * In order for the browser to process the returned data, the server must wrap the data object
10264 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10265 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10266 * depending on whether the callback name was passed:
10269 boolean scriptTag = false;
10270 String cb = request.getParameter("callback");
10273 response.setContentType("text/javascript");
10275 response.setContentType("application/x-json");
10277 Writer out = response.getWriter();
10279 out.write(cb + "(");
10281 out.print(dataBlock.toJsonString());
10288 * @param {Object} config A configuration object.
10290 Roo.data.ScriptTagProxy = function(config){
10291 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10292 Roo.apply(this, config);
10293 this.head = document.getElementsByTagName("head")[0];
10296 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10298 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10300 * @cfg {String} url The URL from which to request the data object.
10303 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10307 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10308 * the server the name of the callback function set up by the load call to process the returned data object.
10309 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10310 * javascript output which calls this named function passing the data object as its only parameter.
10312 callbackParam : "callback",
10314 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10315 * name to the request.
10320 * Load data from the configured URL, read the data object into
10321 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10322 * process that block using the passed callback.
10323 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10324 * for the request to the remote server.
10325 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10326 * object into a block of Roo.data.Records.
10327 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10328 * The function must be passed <ul>
10329 * <li>The Record block object</li>
10330 * <li>The "arg" argument from the load function</li>
10331 * <li>A boolean success indicator</li>
10333 * @param {Object} scope The scope in which to call the callback
10334 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10336 load : function(params, reader, callback, scope, arg){
10337 if(this.fireEvent("beforeload", this, params) !== false){
10339 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10341 var url = this.url;
10342 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10344 url += "&_dc=" + (new Date().getTime());
10346 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10349 cb : "stcCallback"+transId,
10350 scriptId : "stcScript"+transId,
10354 callback : callback,
10360 window[trans.cb] = function(o){
10361 conn.handleResponse(o, trans);
10364 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10366 if(this.autoAbort !== false){
10370 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10372 var script = document.createElement("script");
10373 script.setAttribute("src", url);
10374 script.setAttribute("type", "text/javascript");
10375 script.setAttribute("id", trans.scriptId);
10376 this.head.appendChild(script);
10378 this.trans = trans;
10380 callback.call(scope||this, null, arg, false);
10385 isLoading : function(){
10386 return this.trans ? true : false;
10390 * Abort the current server request.
10392 abort : function(){
10393 if(this.isLoading()){
10394 this.destroyTrans(this.trans);
10399 destroyTrans : function(trans, isLoaded){
10400 this.head.removeChild(document.getElementById(trans.scriptId));
10401 clearTimeout(trans.timeoutId);
10403 window[trans.cb] = undefined;
10405 delete window[trans.cb];
10408 // if hasn't been loaded, wait for load to remove it to prevent script error
10409 window[trans.cb] = function(){
10410 window[trans.cb] = undefined;
10412 delete window[trans.cb];
10419 handleResponse : function(o, trans){
10420 this.trans = false;
10421 this.destroyTrans(trans, true);
10424 result = trans.reader.readRecords(o);
10426 this.fireEvent("loadexception", this, o, trans.arg, e);
10427 trans.callback.call(trans.scope||window, null, trans.arg, false);
10430 this.fireEvent("load", this, o, trans.arg);
10431 trans.callback.call(trans.scope||window, result, trans.arg, true);
10435 handleFailure : function(trans){
10436 this.trans = false;
10437 this.destroyTrans(trans, false);
10438 this.fireEvent("loadexception", this, null, trans.arg);
10439 trans.callback.call(trans.scope||window, null, trans.arg, false);
10443 * Ext JS Library 1.1.1
10444 * Copyright(c) 2006-2007, Ext JS, LLC.
10446 * Originally Released Under LGPL - original licence link has changed is not relivant.
10449 * <script type="text/javascript">
10453 * @class Roo.data.JsonReader
10454 * @extends Roo.data.DataReader
10455 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10456 * based on mappings in a provided Roo.data.Record constructor.
10458 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10459 * in the reply previously.
10464 var RecordDef = Roo.data.Record.create([
10465 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10466 {name: 'occupation'} // This field will use "occupation" as the mapping.
10468 var myReader = new Roo.data.JsonReader({
10469 totalProperty: "results", // The property which contains the total dataset size (optional)
10470 root: "rows", // The property which contains an Array of row objects
10471 id: "id" // The property within each row object that provides an ID for the record (optional)
10475 * This would consume a JSON file like this:
10477 { 'results': 2, 'rows': [
10478 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10479 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10482 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10483 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10484 * paged from the remote server.
10485 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10486 * @cfg {String} root name of the property which contains the Array of row objects.
10487 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10489 * Create a new JsonReader
10490 * @param {Object} meta Metadata configuration options
10491 * @param {Object} recordType Either an Array of field definition objects,
10492 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10494 Roo.data.JsonReader = function(meta, recordType){
10497 // set some defaults:
10498 Roo.applyIf(meta, {
10499 totalProperty: 'total',
10500 successProperty : 'success',
10505 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10507 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10510 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10511 * Used by Store query builder to append _requestMeta to params.
10514 metaFromRemote : false,
10516 * This method is only used by a DataProxy which has retrieved data from a remote server.
10517 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10518 * @return {Object} data A data block which is used by an Roo.data.Store object as
10519 * a cache of Roo.data.Records.
10521 read : function(response){
10522 var json = response.responseText;
10524 var o = /* eval:var:o */ eval("("+json+")");
10526 throw {message: "JsonReader.read: Json object not found"};
10532 this.metaFromRemote = true;
10533 this.meta = o.metaData;
10534 this.recordType = Roo.data.Record.create(o.metaData.fields);
10535 this.onMetaChange(this.meta, this.recordType, o);
10537 return this.readRecords(o);
10540 // private function a store will implement
10541 onMetaChange : function(meta, recordType, o){
10548 simpleAccess: function(obj, subsc) {
10555 getJsonAccessor: function(){
10557 return function(expr) {
10559 return(re.test(expr))
10560 ? new Function("obj", "return obj." + expr)
10565 return Roo.emptyFn;
10570 * Create a data block containing Roo.data.Records from an XML document.
10571 * @param {Object} o An object which contains an Array of row objects in the property specified
10572 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10573 * which contains the total size of the dataset.
10574 * @return {Object} data A data block which is used by an Roo.data.Store object as
10575 * a cache of Roo.data.Records.
10577 readRecords : function(o){
10579 * After any data loads, the raw JSON data is available for further custom processing.
10583 var s = this.meta, Record = this.recordType,
10584 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10586 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10588 if(s.totalProperty) {
10589 this.getTotal = this.getJsonAccessor(s.totalProperty);
10591 if(s.successProperty) {
10592 this.getSuccess = this.getJsonAccessor(s.successProperty);
10594 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10596 var g = this.getJsonAccessor(s.id);
10597 this.getId = function(rec) {
10599 return (r === undefined || r === "") ? null : r;
10602 this.getId = function(){return null;};
10605 for(var jj = 0; jj < fl; jj++){
10607 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10608 this.ef[jj] = this.getJsonAccessor(map);
10612 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10613 if(s.totalProperty){
10614 var vt = parseInt(this.getTotal(o), 10);
10619 if(s.successProperty){
10620 var vs = this.getSuccess(o);
10621 if(vs === false || vs === 'false'){
10626 for(var i = 0; i < c; i++){
10629 var id = this.getId(n);
10630 for(var j = 0; j < fl; j++){
10632 var v = this.ef[j](n);
10634 Roo.log('missing convert for ' + f.name);
10638 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10640 var record = new Record(values, id);
10642 records[i] = record;
10648 totalRecords : totalRecords
10653 * Ext JS Library 1.1.1
10654 * Copyright(c) 2006-2007, Ext JS, LLC.
10656 * Originally Released Under LGPL - original licence link has changed is not relivant.
10659 * <script type="text/javascript">
10663 * @class Roo.data.ArrayReader
10664 * @extends Roo.data.DataReader
10665 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10666 * Each element of that Array represents a row of data fields. The
10667 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10668 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10672 var RecordDef = Roo.data.Record.create([
10673 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10674 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10676 var myReader = new Roo.data.ArrayReader({
10677 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10681 * This would consume an Array like this:
10683 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10685 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10687 * Create a new JsonReader
10688 * @param {Object} meta Metadata configuration options.
10689 * @param {Object} recordType Either an Array of field definition objects
10690 * as specified to {@link Roo.data.Record#create},
10691 * or an {@link Roo.data.Record} object
10692 * created using {@link Roo.data.Record#create}.
10694 Roo.data.ArrayReader = function(meta, recordType){
10695 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10698 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10700 * Create a data block containing Roo.data.Records from an XML document.
10701 * @param {Object} o An Array of row objects which represents the dataset.
10702 * @return {Object} data A data block which is used by an Roo.data.Store object as
10703 * a cache of Roo.data.Records.
10705 readRecords : function(o){
10706 var sid = this.meta ? this.meta.id : null;
10707 var recordType = this.recordType, fields = recordType.prototype.fields;
10710 for(var i = 0; i < root.length; i++){
10713 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10714 for(var j = 0, jlen = fields.length; j < jlen; j++){
10715 var f = fields.items[j];
10716 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10717 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10719 values[f.name] = v;
10721 var record = new recordType(values, id);
10723 records[records.length] = record;
10727 totalRecords : records.length
10736 * @class Roo.bootstrap.ComboBox
10737 * @extends Roo.bootstrap.TriggerField
10738 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10739 * @cfg {Boolean} append (true|false) default false
10740 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10741 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10742 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10743 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10744 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10746 * Create a new ComboBox.
10747 * @param {Object} config Configuration options
10749 Roo.bootstrap.ComboBox = function(config){
10750 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10754 * Fires when the dropdown list is expanded
10755 * @param {Roo.bootstrap.ComboBox} combo This combo box
10760 * Fires when the dropdown list is collapsed
10761 * @param {Roo.bootstrap.ComboBox} combo This combo box
10765 * @event beforeselect
10766 * Fires before a list item is selected. Return false to cancel the selection.
10767 * @param {Roo.bootstrap.ComboBox} combo This combo box
10768 * @param {Roo.data.Record} record The data record returned from the underlying store
10769 * @param {Number} index The index of the selected item in the dropdown list
10771 'beforeselect' : true,
10774 * Fires when a list item is selected
10775 * @param {Roo.bootstrap.ComboBox} combo This combo box
10776 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10777 * @param {Number} index The index of the selected item in the dropdown list
10781 * @event beforequery
10782 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10783 * The event object passed has these properties:
10784 * @param {Roo.bootstrap.ComboBox} combo This combo box
10785 * @param {String} query The query
10786 * @param {Boolean} forceAll true to force "all" query
10787 * @param {Boolean} cancel true to cancel the query
10788 * @param {Object} e The query event object
10790 'beforequery': true,
10793 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10794 * @param {Roo.bootstrap.ComboBox} combo This combo box
10799 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10800 * @param {Roo.bootstrap.ComboBox} combo This combo box
10801 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10806 * Fires when the remove value from the combobox array
10807 * @param {Roo.bootstrap.ComboBox} combo This combo box
10811 * @event specialfilter
10812 * Fires when specialfilter
10813 * @param {Roo.bootstrap.ComboBox} combo This combo box
10815 'specialfilter' : true
10820 this.tickItems = [];
10822 this.selectedIndex = -1;
10823 if(this.mode == 'local'){
10824 if(config.queryDelay === undefined){
10825 this.queryDelay = 10;
10827 if(config.minChars === undefined){
10833 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10836 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10837 * rendering into an Roo.Editor, defaults to false)
10840 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10841 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10844 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10847 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10848 * the dropdown list (defaults to undefined, with no header element)
10852 * @cfg {String/Roo.Template} tpl The template to use to render the output
10856 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10858 listWidth: undefined,
10860 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10861 * mode = 'remote' or 'text' if mode = 'local')
10863 displayField: undefined,
10866 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10867 * mode = 'remote' or 'value' if mode = 'local').
10868 * Note: use of a valueField requires the user make a selection
10869 * in order for a value to be mapped.
10871 valueField: undefined,
10875 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10876 * field's data value (defaults to the underlying DOM element's name)
10878 hiddenName: undefined,
10880 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10884 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10886 selectedClass: 'active',
10889 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10893 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10894 * anchor positions (defaults to 'tl-bl')
10896 listAlign: 'tl-bl?',
10898 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10902 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10903 * query specified by the allQuery config option (defaults to 'query')
10905 triggerAction: 'query',
10907 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10908 * (defaults to 4, does not apply if editable = false)
10912 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10913 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10917 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10918 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10922 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10923 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10927 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10928 * when editable = true (defaults to false)
10930 selectOnFocus:false,
10932 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10934 queryParam: 'query',
10936 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10937 * when mode = 'remote' (defaults to 'Loading...')
10939 loadingText: 'Loading...',
10941 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10945 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10949 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10950 * traditional select (defaults to true)
10954 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10958 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10962 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10963 * listWidth has a higher value)
10967 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10968 * allow the user to set arbitrary text into the field (defaults to false)
10970 forceSelection:false,
10972 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10973 * if typeAhead = true (defaults to 250)
10975 typeAheadDelay : 250,
10977 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10978 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10980 valueNotFoundText : undefined,
10982 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10984 blockFocus : false,
10987 * @cfg {Boolean} disableClear Disable showing of clear button.
10989 disableClear : false,
10991 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10993 alwaysQuery : false,
10996 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11001 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11003 invalidClass : "has-warning",
11006 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11008 validClass : "has-success",
11011 * @cfg {Boolean} specialFilter (true|false) special filter default false
11013 specialFilter : false,
11025 btnPosition : 'right',
11026 triggerList : true,
11027 showToggleBtn : true,
11028 // element that contains real text value.. (when hidden is used..)
11030 getAutoCreate : function()
11037 if(!this.tickable){
11038 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11043 * ComboBox with tickable selections
11046 var align = this.labelAlign || this.parentLabelAlign();
11049 cls : 'form-group roo-combobox-tickable' //input-group
11054 cls : 'tickable-buttons',
11059 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11066 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11073 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11080 buttons.cn.unshift({
11082 cls: 'select2-search-field-input'
11088 Roo.each(buttons.cn, function(c){
11090 c.cls += ' btn-' + _this.size;
11093 if (_this.disabled) {
11104 cls: 'form-hidden-field'
11108 cls: 'select2-choices',
11112 cls: 'select2-search-field',
11124 cls: 'select2-container input-group select2-container-multi',
11129 // cls: 'typeahead typeahead-long dropdown-menu',
11130 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11135 if(this.hasFeedback && !this.allowBlank){
11139 cls: 'glyphicon form-control-feedback'
11142 combobox.cn.push(feedback);
11145 if (align ==='left' && this.fieldLabel.length) {
11147 Roo.log("left and has label");
11153 cls : 'control-label col-sm-' + this.labelWidth,
11154 html : this.fieldLabel
11158 cls : "col-sm-" + (12 - this.labelWidth),
11165 } else if ( this.fieldLabel.length) {
11171 //cls : 'input-group-addon',
11172 html : this.fieldLabel
11182 Roo.log(" no label && no align");
11189 ['xs','sm','md','lg'].map(function(size){
11190 if (settings[size]) {
11191 cfg.cls += ' col-' + size + '-' + settings[size];
11200 initEvents: function()
11204 throw "can not find store for combo";
11206 this.store = Roo.factory(this.store, Roo.data);
11209 this.initTickableEvents();
11213 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11215 if(this.hiddenName){
11217 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11219 this.hiddenField.dom.value =
11220 this.hiddenValue !== undefined ? this.hiddenValue :
11221 this.value !== undefined ? this.value : '';
11223 // prevent input submission
11224 this.el.dom.removeAttribute('name');
11225 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11230 // this.el.dom.setAttribute('autocomplete', 'off');
11233 var cls = 'x-combo-list';
11235 //this.list = new Roo.Layer({
11236 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11242 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11243 _this.list.setWidth(lw);
11246 this.list.on('mouseover', this.onViewOver, this);
11247 this.list.on('mousemove', this.onViewMove, this);
11249 this.list.on('scroll', this.onViewScroll, this);
11252 this.list.swallowEvent('mousewheel');
11253 this.assetHeight = 0;
11256 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11257 this.assetHeight += this.header.getHeight();
11260 this.innerList = this.list.createChild({cls:cls+'-inner'});
11261 this.innerList.on('mouseover', this.onViewOver, this);
11262 this.innerList.on('mousemove', this.onViewMove, this);
11263 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11265 if(this.allowBlank && !this.pageSize && !this.disableClear){
11266 this.footer = this.list.createChild({cls:cls+'-ft'});
11267 this.pageTb = new Roo.Toolbar(this.footer);
11271 this.footer = this.list.createChild({cls:cls+'-ft'});
11272 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11273 {pageSize: this.pageSize});
11277 if (this.pageTb && this.allowBlank && !this.disableClear) {
11279 this.pageTb.add(new Roo.Toolbar.Fill(), {
11280 cls: 'x-btn-icon x-btn-clear',
11282 handler: function()
11285 _this.clearValue();
11286 _this.onSelect(false, -1);
11291 this.assetHeight += this.footer.getHeight();
11296 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11299 this.view = new Roo.View(this.list, this.tpl, {
11300 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11302 //this.view.wrapEl.setDisplayed(false);
11303 this.view.on('click', this.onViewClick, this);
11307 this.store.on('beforeload', this.onBeforeLoad, this);
11308 this.store.on('load', this.onLoad, this);
11309 this.store.on('loadexception', this.onLoadException, this);
11311 if(this.resizable){
11312 this.resizer = new Roo.Resizable(this.list, {
11313 pinned:true, handles:'se'
11315 this.resizer.on('resize', function(r, w, h){
11316 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11317 this.listWidth = w;
11318 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11319 this.restrictHeight();
11321 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11324 if(!this.editable){
11325 this.editable = true;
11326 this.setEditable(false);
11331 if (typeof(this.events.add.listeners) != 'undefined') {
11333 this.addicon = this.wrap.createChild(
11334 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11336 this.addicon.on('click', function(e) {
11337 this.fireEvent('add', this);
11340 if (typeof(this.events.edit.listeners) != 'undefined') {
11342 this.editicon = this.wrap.createChild(
11343 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11344 if (this.addicon) {
11345 this.editicon.setStyle('margin-left', '40px');
11347 this.editicon.on('click', function(e) {
11349 // we fire even if inothing is selected..
11350 this.fireEvent('edit', this, this.lastData );
11356 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11357 "up" : function(e){
11358 this.inKeyMode = true;
11362 "down" : function(e){
11363 if(!this.isExpanded()){
11364 this.onTriggerClick();
11366 this.inKeyMode = true;
11371 "enter" : function(e){
11372 // this.onViewClick();
11376 if(this.fireEvent("specialkey", this, e)){
11377 this.onViewClick(false);
11383 "esc" : function(e){
11387 "tab" : function(e){
11390 if(this.fireEvent("specialkey", this, e)){
11391 this.onViewClick(false);
11399 doRelay : function(foo, bar, hname){
11400 if(hname == 'down' || this.scope.isExpanded()){
11401 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11410 this.queryDelay = Math.max(this.queryDelay || 10,
11411 this.mode == 'local' ? 10 : 250);
11414 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11416 if(this.typeAhead){
11417 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11419 if(this.editable !== false){
11420 this.inputEl().on("keyup", this.onKeyUp, this);
11422 if(this.forceSelection){
11423 this.inputEl().on('blur', this.doForce, this);
11427 this.choices = this.el.select('ul.select2-choices', true).first();
11428 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11432 initTickableEvents: function()
11436 if(this.hiddenName){
11438 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11440 this.hiddenField.dom.value =
11441 this.hiddenValue !== undefined ? this.hiddenValue :
11442 this.value !== undefined ? this.value : '';
11444 // prevent input submission
11445 this.el.dom.removeAttribute('name');
11446 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11451 // this.list = this.el.select('ul.dropdown-menu',true).first();
11453 this.choices = this.el.select('ul.select2-choices', true).first();
11454 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11455 if(this.triggerList){
11456 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11459 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11460 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11462 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11463 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11465 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11466 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11468 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11469 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11470 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11473 this.cancelBtn.hide();
11478 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11479 _this.list.setWidth(lw);
11482 this.list.on('mouseover', this.onViewOver, this);
11483 this.list.on('mousemove', this.onViewMove, this);
11485 this.list.on('scroll', this.onViewScroll, this);
11488 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>';
11491 this.view = new Roo.View(this.list, this.tpl, {
11492 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11495 //this.view.wrapEl.setDisplayed(false);
11496 this.view.on('click', this.onViewClick, this);
11500 this.store.on('beforeload', this.onBeforeLoad, this);
11501 this.store.on('load', this.onLoad, this);
11502 this.store.on('loadexception', this.onLoadException, this);
11505 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11506 "up" : function(e){
11507 this.inKeyMode = true;
11511 "down" : function(e){
11512 this.inKeyMode = true;
11516 "enter" : function(e){
11517 if(this.fireEvent("specialkey", this, e)){
11518 this.onViewClick(false);
11524 "esc" : function(e){
11525 this.onTickableFooterButtonClick(e, false, false);
11528 "tab" : function(e){
11529 this.fireEvent("specialkey", this, e);
11531 this.onTickableFooterButtonClick(e, false, false);
11538 doRelay : function(e, fn, key){
11539 if(this.scope.isExpanded()){
11540 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11549 this.queryDelay = Math.max(this.queryDelay || 10,
11550 this.mode == 'local' ? 10 : 250);
11553 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11555 if(this.typeAhead){
11556 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11559 if(this.editable !== false){
11560 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11565 onDestroy : function(){
11567 this.view.setStore(null);
11568 this.view.el.removeAllListeners();
11569 this.view.el.remove();
11570 this.view.purgeListeners();
11573 this.list.dom.innerHTML = '';
11577 this.store.un('beforeload', this.onBeforeLoad, this);
11578 this.store.un('load', this.onLoad, this);
11579 this.store.un('loadexception', this.onLoadException, this);
11581 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11585 fireKey : function(e){
11586 if(e.isNavKeyPress() && !this.list.isVisible()){
11587 this.fireEvent("specialkey", this, e);
11592 onResize: function(w, h){
11593 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11595 // if(typeof w != 'number'){
11596 // // we do not handle it!?!?
11599 // var tw = this.trigger.getWidth();
11600 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11601 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11603 // this.inputEl().setWidth( this.adjustWidth('input', x));
11605 // //this.trigger.setStyle('left', x+'px');
11607 // if(this.list && this.listWidth === undefined){
11608 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11609 // this.list.setWidth(lw);
11610 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11618 * Allow or prevent the user from directly editing the field text. If false is passed,
11619 * the user will only be able to select from the items defined in the dropdown list. This method
11620 * is the runtime equivalent of setting the 'editable' config option at config time.
11621 * @param {Boolean} value True to allow the user to directly edit the field text
11623 setEditable : function(value){
11624 if(value == this.editable){
11627 this.editable = value;
11629 this.inputEl().dom.setAttribute('readOnly', true);
11630 this.inputEl().on('mousedown', this.onTriggerClick, this);
11631 this.inputEl().addClass('x-combo-noedit');
11633 this.inputEl().dom.setAttribute('readOnly', false);
11634 this.inputEl().un('mousedown', this.onTriggerClick, this);
11635 this.inputEl().removeClass('x-combo-noedit');
11641 onBeforeLoad : function(combo,opts){
11642 if(!this.hasFocus){
11646 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11648 this.restrictHeight();
11649 this.selectedIndex = -1;
11653 onLoad : function(){
11655 this.hasQuery = false;
11657 if(!this.hasFocus){
11661 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11662 this.loading.hide();
11665 if(this.store.getCount() > 0){
11667 this.restrictHeight();
11668 if(this.lastQuery == this.allQuery){
11669 if(this.editable && !this.tickable){
11670 this.inputEl().dom.select();
11674 !this.selectByValue(this.value, true) &&
11677 !this.store.lastOptions ||
11678 typeof(this.store.lastOptions.add) == 'undefined' ||
11679 this.store.lastOptions.add != true
11682 this.select(0, true);
11685 if(this.autoFocus){
11688 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11689 this.taTask.delay(this.typeAheadDelay);
11693 this.onEmptyResults();
11699 onLoadException : function()
11701 this.hasQuery = false;
11703 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11704 this.loading.hide();
11707 if(this.tickable && this.editable){
11713 Roo.log(this.store.reader.jsonData);
11714 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11716 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11722 onTypeAhead : function(){
11723 if(this.store.getCount() > 0){
11724 var r = this.store.getAt(0);
11725 var newValue = r.data[this.displayField];
11726 var len = newValue.length;
11727 var selStart = this.getRawValue().length;
11729 if(selStart != len){
11730 this.setRawValue(newValue);
11731 this.selectText(selStart, newValue.length);
11737 onSelect : function(record, index){
11739 if(this.fireEvent('beforeselect', this, record, index) !== false){
11741 this.setFromData(index > -1 ? record.data : false);
11744 this.fireEvent('select', this, record, index);
11749 * Returns the currently selected field value or empty string if no value is set.
11750 * @return {String} value The selected value
11752 getValue : function(){
11755 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11758 if(this.valueField){
11759 return typeof this.value != 'undefined' ? this.value : '';
11761 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11766 * Clears any text/value currently set in the field
11768 clearValue : function(){
11769 if(this.hiddenField){
11770 this.hiddenField.dom.value = '';
11773 this.setRawValue('');
11774 this.lastSelectionText = '';
11775 this.lastData = false;
11780 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11781 * will be displayed in the field. If the value does not match the data value of an existing item,
11782 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11783 * Otherwise the field will be blank (although the value will still be set).
11784 * @param {String} value The value to match
11786 setValue : function(v){
11793 if(this.valueField){
11794 var r = this.findRecord(this.valueField, v);
11796 text = r.data[this.displayField];
11797 }else if(this.valueNotFoundText !== undefined){
11798 text = this.valueNotFoundText;
11801 this.lastSelectionText = text;
11802 if(this.hiddenField){
11803 this.hiddenField.dom.value = v;
11805 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11809 * @property {Object} the last set data for the element
11814 * Sets the value of the field based on a object which is related to the record format for the store.
11815 * @param {Object} value the value to set as. or false on reset?
11817 setFromData : function(o){
11824 var dv = ''; // display value
11825 var vv = ''; // value value..
11827 if (this.displayField) {
11828 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11830 // this is an error condition!!!
11831 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11834 if(this.valueField){
11835 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11838 if(this.hiddenField){
11839 this.hiddenField.dom.value = vv;
11841 this.lastSelectionText = dv;
11842 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11846 // no hidden field.. - we store the value in 'value', but still display
11847 // display field!!!!
11848 this.lastSelectionText = dv;
11849 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11855 reset : function(){
11856 // overridden so that last data is reset..
11863 this.setValue(this.originalValue);
11864 this.clearInvalid();
11865 this.lastData = false;
11867 this.view.clearSelections();
11871 findRecord : function(prop, value){
11873 if(this.store.getCount() > 0){
11874 this.store.each(function(r){
11875 if(r.data[prop] == value){
11885 getName: function()
11887 // returns hidden if it's set..
11888 if (!this.rendered) {return ''};
11889 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11893 onViewMove : function(e, t){
11894 this.inKeyMode = false;
11898 onViewOver : function(e, t){
11899 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11902 var item = this.view.findItemFromChild(t);
11905 var index = this.view.indexOf(item);
11906 this.select(index, false);
11911 onViewClick : function(view, doFocus, el, e)
11913 var index = this.view.getSelectedIndexes()[0];
11915 var r = this.store.getAt(index);
11919 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11926 Roo.each(this.tickItems, function(v,k){
11928 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11929 _this.tickItems.splice(k, 1);
11931 if(typeof(e) == 'undefined' && view == false){
11932 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11944 this.tickItems.push(r.data);
11946 if(typeof(e) == 'undefined' && view == false){
11947 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11954 this.onSelect(r, index);
11956 if(doFocus !== false && !this.blockFocus){
11957 this.inputEl().focus();
11962 restrictHeight : function(){
11963 //this.innerList.dom.style.height = '';
11964 //var inner = this.innerList.dom;
11965 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11966 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11967 //this.list.beginUpdate();
11968 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11969 this.list.alignTo(this.inputEl(), this.listAlign);
11970 this.list.alignTo(this.inputEl(), this.listAlign);
11971 //this.list.endUpdate();
11975 onEmptyResults : function(){
11977 if(this.tickable && this.editable){
11978 this.restrictHeight();
11986 * Returns true if the dropdown list is expanded, else false.
11988 isExpanded : function(){
11989 return this.list.isVisible();
11993 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11994 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11995 * @param {String} value The data value of the item to select
11996 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11997 * selected item if it is not currently in view (defaults to true)
11998 * @return {Boolean} True if the value matched an item in the list, else false
12000 selectByValue : function(v, scrollIntoView){
12001 if(v !== undefined && v !== null){
12002 var r = this.findRecord(this.valueField || this.displayField, v);
12004 this.select(this.store.indexOf(r), scrollIntoView);
12012 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12013 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12014 * @param {Number} index The zero-based index of the list item to select
12015 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12016 * selected item if it is not currently in view (defaults to true)
12018 select : function(index, scrollIntoView){
12019 this.selectedIndex = index;
12020 this.view.select(index);
12021 if(scrollIntoView !== false){
12022 var el = this.view.getNode(index);
12024 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12027 this.list.scrollChildIntoView(el, false);
12033 selectNext : function(){
12034 var ct = this.store.getCount();
12036 if(this.selectedIndex == -1){
12038 }else if(this.selectedIndex < ct-1){
12039 this.select(this.selectedIndex+1);
12045 selectPrev : function(){
12046 var ct = this.store.getCount();
12048 if(this.selectedIndex == -1){
12050 }else if(this.selectedIndex != 0){
12051 this.select(this.selectedIndex-1);
12057 onKeyUp : function(e){
12058 if(this.editable !== false && !e.isSpecialKey()){
12059 this.lastKey = e.getKey();
12060 this.dqTask.delay(this.queryDelay);
12065 validateBlur : function(){
12066 return !this.list || !this.list.isVisible();
12070 initQuery : function(){
12072 var v = this.getRawValue();
12074 if(this.tickable && this.editable){
12075 v = this.tickableInputEl().getValue();
12082 doForce : function(){
12083 if(this.inputEl().dom.value.length > 0){
12084 this.inputEl().dom.value =
12085 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12091 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12092 * query allowing the query action to be canceled if needed.
12093 * @param {String} query The SQL query to execute
12094 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12095 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12096 * saved in the current store (defaults to false)
12098 doQuery : function(q, forceAll){
12100 if(q === undefined || q === null){
12105 forceAll: forceAll,
12109 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12114 forceAll = qe.forceAll;
12115 if(forceAll === true || (q.length >= this.minChars)){
12117 this.hasQuery = true;
12119 if(this.lastQuery != q || this.alwaysQuery){
12120 this.lastQuery = q;
12121 if(this.mode == 'local'){
12122 this.selectedIndex = -1;
12124 this.store.clearFilter();
12127 if(this.specialFilter){
12128 this.fireEvent('specialfilter', this);
12133 this.store.filter(this.displayField, q);
12136 this.store.fireEvent("datachanged", this.store);
12143 this.store.baseParams[this.queryParam] = q;
12145 var options = {params : this.getParams(q)};
12148 options.add = true;
12149 options.params.start = this.page * this.pageSize;
12152 this.store.load(options);
12155 * this code will make the page width larger, at the beginning, the list not align correctly,
12156 * we should expand the list on onLoad
12157 * so command out it
12162 this.selectedIndex = -1;
12167 this.loadNext = false;
12171 getParams : function(q){
12173 //p[this.queryParam] = q;
12177 p.limit = this.pageSize;
12183 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12185 collapse : function(){
12186 if(!this.isExpanded()){
12193 this.hasFocus = false;
12195 this.cancelBtn.hide();
12196 this.trigger.show();
12199 this.tickableInputEl().dom.value = '';
12200 this.tickableInputEl().blur();
12205 Roo.get(document).un('mousedown', this.collapseIf, this);
12206 Roo.get(document).un('mousewheel', this.collapseIf, this);
12207 if (!this.editable) {
12208 Roo.get(document).un('keydown', this.listKeyPress, this);
12210 this.fireEvent('collapse', this);
12214 collapseIf : function(e){
12215 var in_combo = e.within(this.el);
12216 var in_list = e.within(this.list);
12217 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12219 if (in_combo || in_list || is_list) {
12220 //e.stopPropagation();
12225 this.onTickableFooterButtonClick(e, false, false);
12233 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12235 expand : function(){
12237 if(this.isExpanded() || !this.hasFocus){
12241 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12242 this.list.setWidth(lw);
12249 this.restrictHeight();
12253 this.tickItems = Roo.apply([], this.item);
12256 this.cancelBtn.show();
12257 this.trigger.hide();
12260 this.tickableInputEl().focus();
12265 Roo.get(document).on('mousedown', this.collapseIf, this);
12266 Roo.get(document).on('mousewheel', this.collapseIf, this);
12267 if (!this.editable) {
12268 Roo.get(document).on('keydown', this.listKeyPress, this);
12271 this.fireEvent('expand', this);
12275 // Implements the default empty TriggerField.onTriggerClick function
12276 onTriggerClick : function(e)
12278 Roo.log('trigger click');
12280 if(this.disabled || !this.triggerList){
12285 this.loadNext = false;
12287 if(this.isExpanded()){
12289 if (!this.blockFocus) {
12290 this.inputEl().focus();
12294 this.hasFocus = true;
12295 if(this.triggerAction == 'all') {
12296 this.doQuery(this.allQuery, true);
12298 this.doQuery(this.getRawValue());
12300 if (!this.blockFocus) {
12301 this.inputEl().focus();
12306 onTickableTriggerClick : function(e)
12313 this.loadNext = false;
12314 this.hasFocus = true;
12316 if(this.triggerAction == 'all') {
12317 this.doQuery(this.allQuery, true);
12319 this.doQuery(this.getRawValue());
12323 onSearchFieldClick : function(e)
12325 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12326 this.onTickableFooterButtonClick(e, false, false);
12330 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12335 this.loadNext = false;
12336 this.hasFocus = true;
12338 if(this.triggerAction == 'all') {
12339 this.doQuery(this.allQuery, true);
12341 this.doQuery(this.getRawValue());
12345 listKeyPress : function(e)
12347 //Roo.log('listkeypress');
12348 // scroll to first matching element based on key pres..
12349 if (e.isSpecialKey()) {
12352 var k = String.fromCharCode(e.getKey()).toUpperCase();
12355 var csel = this.view.getSelectedNodes();
12356 var cselitem = false;
12358 var ix = this.view.indexOf(csel[0]);
12359 cselitem = this.store.getAt(ix);
12360 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12366 this.store.each(function(v) {
12368 // start at existing selection.
12369 if (cselitem.id == v.id) {
12375 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12376 match = this.store.indexOf(v);
12382 if (match === false) {
12383 return true; // no more action?
12386 this.view.select(match);
12387 var sn = Roo.get(this.view.getSelectedNodes()[0])
12388 sn.scrollIntoView(sn.dom.parentNode, false);
12391 onViewScroll : function(e, t){
12393 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){
12397 this.hasQuery = true;
12399 this.loading = this.list.select('.loading', true).first();
12401 if(this.loading === null){
12402 this.list.createChild({
12404 cls: 'loading select2-more-results select2-active',
12405 html: 'Loading more results...'
12408 this.loading = this.list.select('.loading', true).first();
12410 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12412 this.loading.hide();
12415 this.loading.show();
12420 this.loadNext = true;
12422 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12427 addItem : function(o)
12429 var dv = ''; // display value
12431 if (this.displayField) {
12432 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12434 // this is an error condition!!!
12435 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12442 var choice = this.choices.createChild({
12444 cls: 'select2-search-choice',
12453 cls: 'select2-search-choice-close',
12458 }, this.searchField);
12460 var close = choice.select('a.select2-search-choice-close', true).first()
12462 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12470 this.inputEl().dom.value = '';
12475 onRemoveItem : function(e, _self, o)
12477 e.preventDefault();
12479 this.lastItem = Roo.apply([], this.item);
12481 var index = this.item.indexOf(o.data) * 1;
12484 Roo.log('not this item?!');
12488 this.item.splice(index, 1);
12493 this.fireEvent('remove', this, e);
12499 syncValue : function()
12501 if(!this.item.length){
12508 Roo.each(this.item, function(i){
12509 if(_this.valueField){
12510 value.push(i[_this.valueField]);
12517 this.value = value.join(',');
12519 if(this.hiddenField){
12520 this.hiddenField.dom.value = this.value;
12523 this.store.fireEvent("datachanged", this.store);
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 Roo.log('get auto create...............');
14663 if (this.carousel) {
14664 cfg.cls += ' carousel slide';
14667 cls : 'carousel-inner'
14670 if(this.bullets > 0){
14673 cls : 'carousel-bullets hidden-xs',
14677 if(this.bullets_cls){
14678 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14681 for (var i = 0; i < this.bullets; i++){
14683 cls : 'bullet bullet-' + i
14691 cfg.cn[0].cn = bullets;
14698 initEvents: function()
14700 Roo.log('-------- init events on tab group ---------');
14704 if(this.bullets > 0){
14706 for (var i = 0; i < this.bullets; i++){
14707 var bullet = this.el.select('.bullet-' + i, true).first();
14713 bullet.on('click', (function(e, el, o, ii, t){
14715 e.preventDefault();
14717 _this.showPanel(ii);
14719 if(_this.autoslide && _this.slideFn){
14720 clearInterval(_this.slideFn);
14721 _this.slideFn = window.setInterval(function() {
14722 _this.showPanelNext();
14726 }).createDelegate(this, [i, bullet], true));
14730 if(this.autoslide){
14731 this.slideFn = window.setInterval(function() {
14732 _this.showPanelNext();
14737 getChildContainer : function()
14739 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14743 * register a Navigation item
14744 * @param {Roo.bootstrap.NavItem} the navitem to add
14746 register : function(item)
14748 this.tabs.push( item);
14749 item.navId = this.navId; // not really needed..
14753 getActivePanel : function()
14756 Roo.each(this.tabs, function(t) {
14766 getPanelByName : function(n)
14769 Roo.each(this.tabs, function(t) {
14770 if (t.tabId == n) {
14778 indexOfPanel : function(p)
14781 Roo.each(this.tabs, function(t,i) {
14782 if (t.tabId == p.tabId) {
14791 * show a specific panel
14792 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14793 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14795 showPanel : function (pan)
14797 if(this.transition){
14798 Roo.log("waiting for the transitionend");
14802 if (typeof(pan) == 'number') {
14803 pan = this.tabs[pan];
14805 if (typeof(pan) == 'string') {
14806 pan = this.getPanelByName(pan);
14808 if (pan.tabId == this.getActivePanel().tabId) {
14811 var cur = this.getActivePanel();
14813 if (false === cur.fireEvent('beforedeactivate')) {
14817 if(this.bullets > 0){
14818 this.setActiveBullet(this.indexOfPanel(pan));
14821 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14823 this.transition = true;
14824 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14825 var lr = dir == 'next' ? 'left' : 'right';
14826 pan.el.addClass(dir); // or prev
14827 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14828 cur.el.addClass(lr); // or right
14829 pan.el.addClass(lr);
14832 cur.el.on('transitionend', function() {
14833 Roo.log("trans end?");
14835 pan.el.removeClass([lr,dir]);
14836 pan.setActive(true);
14838 cur.el.removeClass([lr]);
14839 cur.setActive(false);
14841 _this.transition = false;
14843 }, this, { single: true } );
14848 cur.setActive(false);
14849 pan.setActive(true);
14854 showPanelNext : function()
14856 var i = this.indexOfPanel(this.getActivePanel());
14858 if (i >= this.tabs.length - 1 && !this.autoslide) {
14862 if (i >= this.tabs.length - 1 && this.autoslide) {
14866 this.showPanel(this.tabs[i+1]);
14869 showPanelPrev : function()
14871 var i = this.indexOfPanel(this.getActivePanel());
14873 if (i < 1 && !this.autoslide) {
14877 if (i < 1 && this.autoslide) {
14878 i = this.tabs.length;
14881 this.showPanel(this.tabs[i-1]);
14884 setActiveBullet : function(i)
14886 Roo.each(this.el.select('.bullet', true).elements, function(el){
14887 el.removeClass('selected');
14890 var bullet = this.el.select('.bullet-' + i, true).first();
14896 bullet.addClass('selected');
14907 Roo.apply(Roo.bootstrap.TabGroup, {
14911 * register a Navigation Group
14912 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14914 register : function(navgrp)
14916 this.groups[navgrp.navId] = navgrp;
14920 * fetch a Navigation Group based on the navigation ID
14921 * if one does not exist , it will get created.
14922 * @param {string} the navgroup to add
14923 * @returns {Roo.bootstrap.NavGroup} the navgroup
14925 get: function(navId) {
14926 if (typeof(this.groups[navId]) == 'undefined') {
14927 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14929 return this.groups[navId] ;
14944 * @class Roo.bootstrap.TabPanel
14945 * @extends Roo.bootstrap.Component
14946 * Bootstrap TabPanel class
14947 * @cfg {Boolean} active panel active
14948 * @cfg {String} html panel content
14949 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14950 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14954 * Create a new TabPanel
14955 * @param {Object} config The config object
14958 Roo.bootstrap.TabPanel = function(config){
14959 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14963 * Fires when the active status changes
14964 * @param {Roo.bootstrap.TabPanel} this
14965 * @param {Boolean} state the new state
14970 * @event beforedeactivate
14971 * Fires before a tab is de-activated - can be used to do validation on a form.
14972 * @param {Roo.bootstrap.TabPanel} this
14973 * @return {Boolean} false if there is an error
14976 'beforedeactivate': true
14979 this.tabId = this.tabId || Roo.id();
14983 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14990 getAutoCreate : function(){
14993 // item is needed for carousel - not sure if it has any effect otherwise
14994 cls: 'tab-pane item',
14995 html: this.html || ''
14999 cfg.cls += ' active';
15003 cfg.tabId = this.tabId;
15010 initEvents: function()
15012 Roo.log('-------- init events on tab panel ---------');
15014 var p = this.parent();
15015 this.navId = this.navId || p.navId;
15017 if (typeof(this.navId) != 'undefined') {
15018 // not really needed.. but just in case.. parent should be a NavGroup.
15019 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15020 Roo.log(['register', tg, this]);
15023 var i = tg.tabs.length - 1;
15025 if(this.active && tg.bullets > 0 && i < tg.bullets){
15026 tg.setActiveBullet(i);
15033 onRender : function(ct, position)
15035 // Roo.log("Call onRender: " + this.xtype);
15037 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15045 setActive: function(state)
15047 Roo.log("panel - set active " + this.tabId + "=" + state);
15049 this.active = state;
15051 this.el.removeClass('active');
15053 } else if (!this.el.hasClass('active')) {
15054 this.el.addClass('active');
15057 this.fireEvent('changed', this, state);
15074 * @class Roo.bootstrap.DateField
15075 * @extends Roo.bootstrap.Input
15076 * Bootstrap DateField class
15077 * @cfg {Number} weekStart default 0
15078 * @cfg {String} viewMode default empty, (months|years)
15079 * @cfg {String} minViewMode default empty, (months|years)
15080 * @cfg {Number} startDate default -Infinity
15081 * @cfg {Number} endDate default Infinity
15082 * @cfg {Boolean} todayHighlight default false
15083 * @cfg {Boolean} todayBtn default false
15084 * @cfg {Boolean} calendarWeeks default false
15085 * @cfg {Object} daysOfWeekDisabled default empty
15086 * @cfg {Boolean} singleMode default false (true | false)
15088 * @cfg {Boolean} keyboardNavigation default true
15089 * @cfg {String} language default en
15092 * Create a new DateField
15093 * @param {Object} config The config object
15096 Roo.bootstrap.DateField = function(config){
15097 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15101 * Fires when this field show.
15102 * @param {Roo.bootstrap.DateField} this
15103 * @param {Mixed} date The date value
15108 * Fires when this field hide.
15109 * @param {Roo.bootstrap.DateField} this
15110 * @param {Mixed} date The date value
15115 * Fires when select a date.
15116 * @param {Roo.bootstrap.DateField} this
15117 * @param {Mixed} date The date value
15123 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15126 * @cfg {String} format
15127 * The default date format string which can be overriden for localization support. The format must be
15128 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15132 * @cfg {String} altFormats
15133 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15134 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15136 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15144 todayHighlight : false,
15150 keyboardNavigation: true,
15152 calendarWeeks: false,
15154 startDate: -Infinity,
15158 daysOfWeekDisabled: [],
15162 singleMode : false,
15164 UTCDate: function()
15166 return new Date(Date.UTC.apply(Date, arguments));
15169 UTCToday: function()
15171 var today = new Date();
15172 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15175 getDate: function() {
15176 var d = this.getUTCDate();
15177 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15180 getUTCDate: function() {
15184 setDate: function(d) {
15185 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15188 setUTCDate: function(d) {
15190 this.setValue(this.formatDate(this.date));
15193 onRender: function(ct, position)
15196 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15198 this.language = this.language || 'en';
15199 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15200 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15202 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15203 this.format = this.format || 'm/d/y';
15204 this.isInline = false;
15205 this.isInput = true;
15206 this.component = this.el.select('.add-on', true).first() || false;
15207 this.component = (this.component && this.component.length === 0) ? false : this.component;
15208 this.hasInput = this.component && this.inputEL().length;
15210 if (typeof(this.minViewMode === 'string')) {
15211 switch (this.minViewMode) {
15213 this.minViewMode = 1;
15216 this.minViewMode = 2;
15219 this.minViewMode = 0;
15224 if (typeof(this.viewMode === 'string')) {
15225 switch (this.viewMode) {
15238 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15240 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15242 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15244 this.picker().on('mousedown', this.onMousedown, this);
15245 this.picker().on('click', this.onClick, this);
15247 this.picker().addClass('datepicker-dropdown');
15249 this.startViewMode = this.viewMode;
15251 if(this.singleMode){
15252 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15253 v.setVisibilityMode(Roo.Element.DISPLAY)
15257 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15258 v.setStyle('width', '189px');
15262 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15263 if(!this.calendarWeeks){
15268 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15269 v.attr('colspan', function(i, val){
15270 return parseInt(val) + 1;
15275 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15277 this.setStartDate(this.startDate);
15278 this.setEndDate(this.endDate);
15280 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15287 if(this.isInline) {
15292 picker : function()
15294 return this.pickerEl;
15295 // return this.el.select('.datepicker', true).first();
15298 fillDow: function()
15300 var dowCnt = this.weekStart;
15309 if(this.calendarWeeks){
15317 while (dowCnt < this.weekStart + 7) {
15321 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15325 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15328 fillMonths: function()
15331 var months = this.picker().select('>.datepicker-months td', true).first();
15333 months.dom.innerHTML = '';
15339 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15342 months.createChild(month);
15349 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;
15351 if (this.date < this.startDate) {
15352 this.viewDate = new Date(this.startDate);
15353 } else if (this.date > this.endDate) {
15354 this.viewDate = new Date(this.endDate);
15356 this.viewDate = new Date(this.date);
15364 var d = new Date(this.viewDate),
15365 year = d.getUTCFullYear(),
15366 month = d.getUTCMonth(),
15367 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15368 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15369 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15370 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15371 currentDate = this.date && this.date.valueOf(),
15372 today = this.UTCToday();
15374 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15376 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15378 // this.picker.select('>tfoot th.today').
15379 // .text(dates[this.language].today)
15380 // .toggle(this.todayBtn !== false);
15382 this.updateNavArrows();
15385 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15387 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15389 prevMonth.setUTCDate(day);
15391 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15393 var nextMonth = new Date(prevMonth);
15395 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15397 nextMonth = nextMonth.valueOf();
15399 var fillMonths = false;
15401 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15403 while(prevMonth.valueOf() < nextMonth) {
15406 if (prevMonth.getUTCDay() === this.weekStart) {
15408 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15416 if(this.calendarWeeks){
15417 // ISO 8601: First week contains first thursday.
15418 // ISO also states week starts on Monday, but we can be more abstract here.
15420 // Start of current week: based on weekstart/current date
15421 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15422 // Thursday of this week
15423 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15424 // First Thursday of year, year from thursday
15425 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15426 // Calendar week: ms between thursdays, div ms per day, div 7 days
15427 calWeek = (th - yth) / 864e5 / 7 + 1;
15429 fillMonths.cn.push({
15437 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15439 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15442 if (this.todayHighlight &&
15443 prevMonth.getUTCFullYear() == today.getFullYear() &&
15444 prevMonth.getUTCMonth() == today.getMonth() &&
15445 prevMonth.getUTCDate() == today.getDate()) {
15446 clsName += ' today';
15449 if (currentDate && prevMonth.valueOf() === currentDate) {
15450 clsName += ' active';
15453 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15454 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15455 clsName += ' disabled';
15458 fillMonths.cn.push({
15460 cls: 'day ' + clsName,
15461 html: prevMonth.getDate()
15464 prevMonth.setDate(prevMonth.getDate()+1);
15467 var currentYear = this.date && this.date.getUTCFullYear();
15468 var currentMonth = this.date && this.date.getUTCMonth();
15470 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15472 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15473 v.removeClass('active');
15475 if(currentYear === year && k === currentMonth){
15476 v.addClass('active');
15479 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15480 v.addClass('disabled');
15486 year = parseInt(year/10, 10) * 10;
15488 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15490 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15493 for (var i = -1; i < 11; i++) {
15494 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15496 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15504 showMode: function(dir)
15507 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15510 Roo.each(this.picker().select('>div',true).elements, function(v){
15511 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15514 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15519 if(this.isInline) return;
15521 this.picker().removeClass(['bottom', 'top']);
15523 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15525 * place to the top of element!
15529 this.picker().addClass('top');
15530 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15535 this.picker().addClass('bottom');
15537 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15540 parseDate : function(value)
15542 if(!value || value instanceof Date){
15545 var v = Date.parseDate(value, this.format);
15546 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15547 v = Date.parseDate(value, 'Y-m-d');
15549 if(!v && this.altFormats){
15550 if(!this.altFormatsArray){
15551 this.altFormatsArray = this.altFormats.split("|");
15553 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15554 v = Date.parseDate(value, this.altFormatsArray[i]);
15560 formatDate : function(date, fmt)
15562 return (!date || !(date instanceof Date)) ?
15563 date : date.dateFormat(fmt || this.format);
15566 onFocus : function()
15568 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15572 onBlur : function()
15574 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15576 var d = this.inputEl().getValue();
15585 this.picker().show();
15589 this.fireEvent('show', this, this.date);
15594 if(this.isInline) return;
15595 this.picker().hide();
15596 this.viewMode = this.startViewMode;
15599 this.fireEvent('hide', this, this.date);
15603 onMousedown: function(e)
15605 e.stopPropagation();
15606 e.preventDefault();
15611 Roo.bootstrap.DateField.superclass.keyup.call(this);
15615 setValue: function(v)
15618 // v can be a string or a date..
15621 var d = new Date(this.parseDate(v) ).clearTime();
15623 if(isNaN(d.getTime())){
15624 this.date = this.viewDate = '';
15625 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15629 v = this.formatDate(d);
15631 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15633 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15637 this.fireEvent('select', this, this.date);
15641 getValue: function()
15643 return this.formatDate(this.date);
15646 fireKey: function(e)
15648 if (!this.picker().isVisible()){
15649 if (e.keyCode == 27) // allow escape to hide and re-show picker
15654 var dateChanged = false,
15656 newDate, newViewDate;
15661 e.preventDefault();
15665 if (!this.keyboardNavigation) break;
15666 dir = e.keyCode == 37 ? -1 : 1;
15669 newDate = this.moveYear(this.date, dir);
15670 newViewDate = this.moveYear(this.viewDate, dir);
15671 } else if (e.shiftKey){
15672 newDate = this.moveMonth(this.date, dir);
15673 newViewDate = this.moveMonth(this.viewDate, dir);
15675 newDate = new Date(this.date);
15676 newDate.setUTCDate(this.date.getUTCDate() + dir);
15677 newViewDate = new Date(this.viewDate);
15678 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15680 if (this.dateWithinRange(newDate)){
15681 this.date = newDate;
15682 this.viewDate = newViewDate;
15683 this.setValue(this.formatDate(this.date));
15685 e.preventDefault();
15686 dateChanged = true;
15691 if (!this.keyboardNavigation) break;
15692 dir = e.keyCode == 38 ? -1 : 1;
15694 newDate = this.moveYear(this.date, dir);
15695 newViewDate = this.moveYear(this.viewDate, dir);
15696 } else if (e.shiftKey){
15697 newDate = this.moveMonth(this.date, dir);
15698 newViewDate = this.moveMonth(this.viewDate, dir);
15700 newDate = new Date(this.date);
15701 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15702 newViewDate = new Date(this.viewDate);
15703 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15705 if (this.dateWithinRange(newDate)){
15706 this.date = newDate;
15707 this.viewDate = newViewDate;
15708 this.setValue(this.formatDate(this.date));
15710 e.preventDefault();
15711 dateChanged = true;
15715 this.setValue(this.formatDate(this.date));
15717 e.preventDefault();
15720 this.setValue(this.formatDate(this.date));
15734 onClick: function(e)
15736 e.stopPropagation();
15737 e.preventDefault();
15739 var target = e.getTarget();
15741 if(target.nodeName.toLowerCase() === 'i'){
15742 target = Roo.get(target).dom.parentNode;
15745 var nodeName = target.nodeName;
15746 var className = target.className;
15747 var html = target.innerHTML;
15748 //Roo.log(nodeName);
15750 switch(nodeName.toLowerCase()) {
15752 switch(className) {
15758 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15759 switch(this.viewMode){
15761 this.viewDate = this.moveMonth(this.viewDate, dir);
15765 this.viewDate = this.moveYear(this.viewDate, dir);
15771 var date = new Date();
15772 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15774 this.setValue(this.formatDate(this.date));
15781 if (className.indexOf('disabled') < 0) {
15782 this.viewDate.setUTCDate(1);
15783 if (className.indexOf('month') > -1) {
15784 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15786 var year = parseInt(html, 10) || 0;
15787 this.viewDate.setUTCFullYear(year);
15791 if(this.singleMode){
15792 this.setValue(this.formatDate(this.viewDate));
15803 //Roo.log(className);
15804 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15805 var day = parseInt(html, 10) || 1;
15806 var year = this.viewDate.getUTCFullYear(),
15807 month = this.viewDate.getUTCMonth();
15809 if (className.indexOf('old') > -1) {
15816 } else if (className.indexOf('new') > -1) {
15824 //Roo.log([year,month,day]);
15825 this.date = this.UTCDate(year, month, day,0,0,0,0);
15826 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15828 //Roo.log(this.formatDate(this.date));
15829 this.setValue(this.formatDate(this.date));
15836 setStartDate: function(startDate)
15838 this.startDate = startDate || -Infinity;
15839 if (this.startDate !== -Infinity) {
15840 this.startDate = this.parseDate(this.startDate);
15843 this.updateNavArrows();
15846 setEndDate: function(endDate)
15848 this.endDate = endDate || Infinity;
15849 if (this.endDate !== Infinity) {
15850 this.endDate = this.parseDate(this.endDate);
15853 this.updateNavArrows();
15856 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15858 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15859 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15860 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15862 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15863 return parseInt(d, 10);
15866 this.updateNavArrows();
15869 updateNavArrows: function()
15871 if(this.singleMode){
15875 var d = new Date(this.viewDate),
15876 year = d.getUTCFullYear(),
15877 month = d.getUTCMonth();
15879 Roo.each(this.picker().select('.prev', true).elements, function(v){
15881 switch (this.viewMode) {
15884 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15890 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15897 Roo.each(this.picker().select('.next', true).elements, function(v){
15899 switch (this.viewMode) {
15902 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15908 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15916 moveMonth: function(date, dir)
15918 if (!dir) return date;
15919 var new_date = new Date(date.valueOf()),
15920 day = new_date.getUTCDate(),
15921 month = new_date.getUTCMonth(),
15922 mag = Math.abs(dir),
15924 dir = dir > 0 ? 1 : -1;
15927 // If going back one month, make sure month is not current month
15928 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15930 return new_date.getUTCMonth() == month;
15932 // If going forward one month, make sure month is as expected
15933 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15935 return new_date.getUTCMonth() != new_month;
15937 new_month = month + dir;
15938 new_date.setUTCMonth(new_month);
15939 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15940 if (new_month < 0 || new_month > 11)
15941 new_month = (new_month + 12) % 12;
15943 // For magnitudes >1, move one month at a time...
15944 for (var i=0; i<mag; i++)
15945 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15946 new_date = this.moveMonth(new_date, dir);
15947 // ...then reset the day, keeping it in the new month
15948 new_month = new_date.getUTCMonth();
15949 new_date.setUTCDate(day);
15951 return new_month != new_date.getUTCMonth();
15954 // Common date-resetting loop -- if date is beyond end of month, make it
15957 new_date.setUTCDate(--day);
15958 new_date.setUTCMonth(new_month);
15963 moveYear: function(date, dir)
15965 return this.moveMonth(date, dir*12);
15968 dateWithinRange: function(date)
15970 return date >= this.startDate && date <= this.endDate;
15976 this.picker().remove();
15981 Roo.apply(Roo.bootstrap.DateField, {
15992 html: '<i class="fa fa-arrow-left"/>'
16002 html: '<i class="fa fa-arrow-right"/>'
16044 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16045 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16046 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16047 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16048 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16061 navFnc: 'FullYear',
16066 navFnc: 'FullYear',
16071 Roo.apply(Roo.bootstrap.DateField, {
16075 cls: 'datepicker dropdown-menu roo-dynamic',
16079 cls: 'datepicker-days',
16083 cls: 'table-condensed',
16085 Roo.bootstrap.DateField.head,
16089 Roo.bootstrap.DateField.footer
16096 cls: 'datepicker-months',
16100 cls: 'table-condensed',
16102 Roo.bootstrap.DateField.head,
16103 Roo.bootstrap.DateField.content,
16104 Roo.bootstrap.DateField.footer
16111 cls: 'datepicker-years',
16115 cls: 'table-condensed',
16117 Roo.bootstrap.DateField.head,
16118 Roo.bootstrap.DateField.content,
16119 Roo.bootstrap.DateField.footer
16138 * @class Roo.bootstrap.TimeField
16139 * @extends Roo.bootstrap.Input
16140 * Bootstrap DateField class
16144 * Create a new TimeField
16145 * @param {Object} config The config object
16148 Roo.bootstrap.TimeField = function(config){
16149 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16153 * Fires when this field show.
16154 * @param {Roo.bootstrap.DateField} thisthis
16155 * @param {Mixed} date The date value
16160 * Fires when this field hide.
16161 * @param {Roo.bootstrap.DateField} this
16162 * @param {Mixed} date The date value
16167 * Fires when select a date.
16168 * @param {Roo.bootstrap.DateField} this
16169 * @param {Mixed} date The date value
16175 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16178 * @cfg {String} format
16179 * The default time format string which can be overriden for localization support. The format must be
16180 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16184 onRender: function(ct, position)
16187 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16189 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16191 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16193 this.pop = this.picker().select('>.datepicker-time',true).first();
16194 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16196 this.picker().on('mousedown', this.onMousedown, this);
16197 this.picker().on('click', this.onClick, this);
16199 this.picker().addClass('datepicker-dropdown');
16204 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16205 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16206 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16207 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16208 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16209 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16213 fireKey: function(e){
16214 if (!this.picker().isVisible()){
16215 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16221 e.preventDefault();
16229 this.onTogglePeriod();
16232 this.onIncrementMinutes();
16235 this.onDecrementMinutes();
16244 onClick: function(e) {
16245 e.stopPropagation();
16246 e.preventDefault();
16249 picker : function()
16251 return this.el.select('.datepicker', true).first();
16254 fillTime: function()
16256 var time = this.pop.select('tbody', true).first();
16258 time.dom.innerHTML = '';
16273 cls: 'hours-up glyphicon glyphicon-chevron-up'
16293 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16314 cls: 'timepicker-hour',
16329 cls: 'timepicker-minute',
16344 cls: 'btn btn-primary period',
16366 cls: 'hours-down glyphicon glyphicon-chevron-down'
16386 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16404 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16411 var hours = this.time.getHours();
16412 var minutes = this.time.getMinutes();
16425 hours = hours - 12;
16429 hours = '0' + hours;
16433 minutes = '0' + minutes;
16436 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16437 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16438 this.pop.select('button', true).first().dom.innerHTML = period;
16444 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16446 var cls = ['bottom'];
16448 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16455 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16460 this.picker().addClass(cls.join('-'));
16464 Roo.each(cls, function(c){
16466 _this.picker().setTop(_this.inputEl().getHeight());
16470 _this.picker().setTop(0 - _this.picker().getHeight());
16475 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16479 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16486 onFocus : function()
16488 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16492 onBlur : function()
16494 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16500 this.picker().show();
16505 this.fireEvent('show', this, this.date);
16510 this.picker().hide();
16513 this.fireEvent('hide', this, this.date);
16516 setTime : function()
16519 this.setValue(this.time.format(this.format));
16521 this.fireEvent('select', this, this.date);
16526 onMousedown: function(e){
16527 e.stopPropagation();
16528 e.preventDefault();
16531 onIncrementHours: function()
16533 Roo.log('onIncrementHours');
16534 this.time = this.time.add(Date.HOUR, 1);
16539 onDecrementHours: function()
16541 Roo.log('onDecrementHours');
16542 this.time = this.time.add(Date.HOUR, -1);
16546 onIncrementMinutes: function()
16548 Roo.log('onIncrementMinutes');
16549 this.time = this.time.add(Date.MINUTE, 1);
16553 onDecrementMinutes: function()
16555 Roo.log('onDecrementMinutes');
16556 this.time = this.time.add(Date.MINUTE, -1);
16560 onTogglePeriod: function()
16562 Roo.log('onTogglePeriod');
16563 this.time = this.time.add(Date.HOUR, 12);
16570 Roo.apply(Roo.bootstrap.TimeField, {
16600 cls: 'btn btn-info ok',
16612 Roo.apply(Roo.bootstrap.TimeField, {
16616 cls: 'datepicker dropdown-menu',
16620 cls: 'datepicker-time',
16624 cls: 'table-condensed',
16626 Roo.bootstrap.TimeField.content,
16627 Roo.bootstrap.TimeField.footer
16646 * @class Roo.bootstrap.MonthField
16647 * @extends Roo.bootstrap.Input
16648 * Bootstrap MonthField class
16650 * @cfg {String} language default en
16653 * Create a new MonthField
16654 * @param {Object} config The config object
16657 Roo.bootstrap.MonthField = function(config){
16658 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16663 * Fires when this field show.
16664 * @param {Roo.bootstrap.MonthField} this
16665 * @param {Mixed} date The date value
16670 * Fires when this field hide.
16671 * @param {Roo.bootstrap.MonthField} this
16672 * @param {Mixed} date The date value
16677 * Fires when select a date.
16678 * @param {Roo.bootstrap.MonthField} this
16679 * @param {String} oldvalue The old value
16680 * @param {String} newvalue The new value
16686 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16688 onRender: function(ct, position)
16691 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16693 this.language = this.language || 'en';
16694 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16695 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16697 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16698 this.isInline = false;
16699 this.isInput = true;
16700 this.component = this.el.select('.add-on', true).first() || false;
16701 this.component = (this.component && this.component.length === 0) ? false : this.component;
16702 this.hasInput = this.component && this.inputEL().length;
16704 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16706 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16708 this.picker().on('mousedown', this.onMousedown, this);
16709 this.picker().on('click', this.onClick, this);
16711 this.picker().addClass('datepicker-dropdown');
16713 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16714 v.setStyle('width', '189px');
16721 if(this.isInline) {
16727 setValue: function(v, suppressEvent)
16729 var o = this.getValue();
16731 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16735 if(suppressEvent !== true){
16736 this.fireEvent('select', this, o, v);
16741 getValue: function()
16746 onClick: function(e)
16748 e.stopPropagation();
16749 e.preventDefault();
16751 var target = e.getTarget();
16753 if(target.nodeName.toLowerCase() === 'i'){
16754 target = Roo.get(target).dom.parentNode;
16757 var nodeName = target.nodeName;
16758 var className = target.className;
16759 var html = target.innerHTML;
16761 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16765 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16767 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16773 picker : function()
16775 return this.pickerEl;
16778 fillMonths: function()
16781 var months = this.picker().select('>.datepicker-months td', true).first();
16783 months.dom.innerHTML = '';
16789 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16792 months.createChild(month);
16801 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16802 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16805 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16806 e.removeClass('active');
16808 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16809 e.addClass('active');
16816 if(this.isInline) return;
16818 this.picker().removeClass(['bottom', 'top']);
16820 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16822 * place to the top of element!
16826 this.picker().addClass('top');
16827 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16832 this.picker().addClass('bottom');
16834 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16837 onFocus : function()
16839 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16843 onBlur : function()
16845 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16847 var d = this.inputEl().getValue();
16856 this.picker().show();
16857 this.picker().select('>.datepicker-months', true).first().show();
16861 this.fireEvent('show', this, this.date);
16866 if(this.isInline) return;
16867 this.picker().hide();
16868 this.fireEvent('hide', this, this.date);
16872 onMousedown: function(e)
16874 e.stopPropagation();
16875 e.preventDefault();
16880 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16884 fireKey: function(e)
16886 if (!this.picker().isVisible()){
16887 if (e.keyCode == 27) // allow escape to hide and re-show picker
16897 e.preventDefault();
16901 dir = e.keyCode == 37 ? -1 : 1;
16903 this.vIndex = this.vIndex + dir;
16905 if(this.vIndex < 0){
16909 if(this.vIndex > 11){
16913 if(isNaN(this.vIndex)){
16917 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16923 dir = e.keyCode == 38 ? -1 : 1;
16925 this.vIndex = this.vIndex + dir * 4;
16927 if(this.vIndex < 0){
16931 if(this.vIndex > 11){
16935 if(isNaN(this.vIndex)){
16939 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16944 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16945 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16949 e.preventDefault();
16952 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16953 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16969 this.picker().remove();
16974 Roo.apply(Roo.bootstrap.MonthField, {
16993 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16994 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16999 Roo.apply(Roo.bootstrap.MonthField, {
17003 cls: 'datepicker dropdown-menu roo-dynamic',
17007 cls: 'datepicker-months',
17011 cls: 'table-condensed',
17013 Roo.bootstrap.DateField.content
17033 * @class Roo.bootstrap.CheckBox
17034 * @extends Roo.bootstrap.Input
17035 * Bootstrap CheckBox class
17037 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17038 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17039 * @cfg {String} boxLabel The text that appears beside the checkbox
17040 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17041 * @cfg {Boolean} checked initnal the element
17042 * @cfg {Boolean} inline inline the element (default false)
17043 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17046 * Create a new CheckBox
17047 * @param {Object} config The config object
17050 Roo.bootstrap.CheckBox = function(config){
17051 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17056 * Fires when the element is checked or unchecked.
17057 * @param {Roo.bootstrap.CheckBox} this This input
17058 * @param {Boolean} checked The new checked value
17065 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17067 inputType: 'checkbox',
17075 getAutoCreate : function()
17077 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17083 cfg.cls = 'form-group ' + this.inputType; //input-group
17086 cfg.cls += ' ' + this.inputType + '-inline';
17092 type : this.inputType,
17093 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17094 cls : 'roo-' + this.inputType, //'form-box',
17095 placeholder : this.placeholder || ''
17099 if (this.weight) { // Validity check?
17100 cfg.cls += " " + this.inputType + "-" + this.weight;
17103 if (this.disabled) {
17104 input.disabled=true;
17108 input.checked = this.checked;
17112 input.name = this.name;
17116 input.cls += ' input-' + this.size;
17121 ['xs','sm','md','lg'].map(function(size){
17122 if (settings[size]) {
17123 cfg.cls += ' col-' + size + '-' + settings[size];
17127 var inputblock = input;
17129 if (this.before || this.after) {
17132 cls : 'input-group',
17137 inputblock.cn.push({
17139 cls : 'input-group-addon',
17144 inputblock.cn.push(input);
17147 inputblock.cn.push({
17149 cls : 'input-group-addon',
17156 if (align ==='left' && this.fieldLabel.length) {
17157 Roo.log("left and has label");
17163 cls : 'control-label col-md-' + this.labelWidth,
17164 html : this.fieldLabel
17168 cls : "col-md-" + (12 - this.labelWidth),
17175 } else if ( this.fieldLabel.length) {
17180 tag: this.boxLabel ? 'span' : 'label',
17182 cls: 'control-label box-input-label',
17183 //cls : 'input-group-addon',
17184 html : this.fieldLabel
17194 Roo.log(" no label && no align");
17195 cfg.cn = [ inputblock ] ;
17200 var boxLabelCfg = {
17202 //'for': id, // box label is handled by onclick - so no for...
17204 html: this.boxLabel
17208 boxLabelCfg.tooltip = this.tooltip;
17211 cfg.cn.push(boxLabelCfg);
17221 * return the real input element.
17223 inputEl: function ()
17225 return this.el.select('input.roo-' + this.inputType,true).first();
17228 labelEl: function()
17230 return this.el.select('label.control-label',true).first();
17232 /* depricated... */
17236 return this.labelEl();
17239 initEvents : function()
17241 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17243 this.inputEl().on('click', this.onClick, this);
17245 if (this.boxLabel) {
17246 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17249 this.startValue = this.getValue();
17252 Roo.bootstrap.CheckBox.register(this);
17256 onClick : function()
17258 this.setChecked(!this.checked);
17261 setChecked : function(state,suppressEvent)
17263 this.startValue = this.getValue();
17265 if(this.inputType == 'radio'){
17267 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17268 e.dom.checked = false;
17271 this.inputEl().dom.checked = true;
17273 this.inputEl().dom.value = this.inputValue;
17275 if(suppressEvent !== true){
17276 this.fireEvent('check', this, true);
17284 this.checked = state;
17286 this.inputEl().dom.checked = state;
17288 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17290 if(suppressEvent !== true){
17291 this.fireEvent('check', this, state);
17297 getValue : function()
17299 if(this.inputType == 'radio'){
17300 return this.getGroupValue();
17303 return this.inputEl().getValue();
17307 getGroupValue : function()
17309 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17313 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17316 setValue : function(v,suppressEvent)
17318 if(this.inputType == 'radio'){
17319 this.setGroupValue(v, suppressEvent);
17323 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17328 setGroupValue : function(v, suppressEvent)
17330 this.startValue = this.getValue();
17332 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17333 e.dom.checked = false;
17335 if(e.dom.value == v){
17336 e.dom.checked = true;
17340 if(suppressEvent !== true){
17341 this.fireEvent('check', this, true);
17349 validate : function()
17353 (this.inputType == 'radio' && this.validateRadio()) ||
17354 (this.inputType == 'checkbox' && this.validateCheckbox())
17360 this.markInvalid();
17364 validateRadio : function()
17368 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17369 if(!e.dom.checked){
17381 validateCheckbox : function()
17384 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17387 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17395 for(var i in group){
17400 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17407 * Mark this field as valid
17409 markValid : function()
17411 if(this.allowBlank){
17417 this.fireEvent('valid', this);
17419 if(this.inputType == 'radio'){
17420 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17421 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17422 e.findParent('.form-group', false, true).addClass(_this.validClass);
17429 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17430 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17434 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17440 for(var i in group){
17441 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17442 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17447 * Mark this field as invalid
17448 * @param {String} msg The validation message
17450 markInvalid : function(msg)
17452 if(this.allowBlank){
17458 this.fireEvent('invalid', this, msg);
17460 if(this.inputType == 'radio'){
17461 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17462 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17463 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17470 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17471 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17475 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17481 for(var i in group){
17482 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17483 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17490 Roo.apply(Roo.bootstrap.CheckBox, {
17495 * register a CheckBox Group
17496 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17498 register : function(checkbox)
17500 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17501 this.groups[checkbox.groupId] = {};
17504 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17508 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17512 * fetch a CheckBox Group based on the group ID
17513 * @param {string} the group ID
17514 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17516 get: function(groupId) {
17517 if (typeof(this.groups[groupId]) == 'undefined') {
17521 return this.groups[groupId] ;
17533 *<div class="radio">
17535 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17536 Option one is this and that—be sure to include why it's great
17543 *<label class="radio-inline">fieldLabel</label>
17544 *<label class="radio-inline">
17545 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17553 * @class Roo.bootstrap.Radio
17554 * @extends Roo.bootstrap.CheckBox
17555 * Bootstrap Radio class
17558 * Create a new Radio
17559 * @param {Object} config The config object
17562 Roo.bootstrap.Radio = function(config){
17563 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17567 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17569 inputType: 'radio',
17573 getAutoCreate : function()
17575 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17576 align = align || 'left'; // default...
17583 tag : this.inline ? 'span' : 'div',
17588 var inline = this.inline ? ' radio-inline' : '';
17592 // does not need for, as we wrap the input with it..
17594 cls : 'control-label box-label' + inline,
17597 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17601 //cls : 'control-label' + inline,
17602 html : this.fieldLabel,
17603 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17612 type : this.inputType,
17613 //value : (!this.checked) ? this.valueOff : this.inputValue,
17614 value : this.inputValue,
17616 placeholder : this.placeholder || '' // ?? needed????
17619 if (this.weight) { // Validity check?
17620 input.cls += " radio-" + this.weight;
17622 if (this.disabled) {
17623 input.disabled=true;
17627 input.checked = this.checked;
17631 input.name = this.name;
17635 input.cls += ' input-' + this.size;
17638 //?? can span's inline have a width??
17641 ['xs','sm','md','lg'].map(function(size){
17642 if (settings[size]) {
17643 cfg.cls += ' col-' + size + '-' + settings[size];
17647 var inputblock = input;
17649 if (this.before || this.after) {
17652 cls : 'input-group',
17657 inputblock.cn.push({
17659 cls : 'input-group-addon',
17663 inputblock.cn.push(input);
17665 inputblock.cn.push({
17667 cls : 'input-group-addon',
17675 if (this.fieldLabel && this.fieldLabel.length) {
17676 cfg.cn.push(fieldLabel);
17679 // normal bootstrap puts the input inside the label.
17680 // however with our styled version - it has to go after the input.
17682 //lbl.cn.push(inputblock);
17686 cls: 'radio' + inline,
17693 cfg.cn.push( lblwrap);
17698 html: this.boxLabel
17707 initEvents : function()
17709 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17711 this.inputEl().on('click', this.onClick, this);
17712 if (this.boxLabel) {
17713 Roo.log('find label')
17714 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17719 inputEl: function ()
17721 return this.el.select('input.roo-radio',true).first();
17723 onClick : function()
17726 this.setChecked(true);
17729 setChecked : function(state,suppressEvent)
17732 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17733 v.dom.checked = false;
17736 Roo.log(this.inputEl().dom);
17737 this.checked = state;
17738 this.inputEl().dom.checked = state;
17740 if(suppressEvent !== true){
17741 this.fireEvent('check', this, state);
17744 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17748 getGroupValue : function()
17751 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17752 if(v.dom.checked == true){
17753 value = v.dom.value;
17761 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17762 * @return {Mixed} value The field value
17764 getValue : function(){
17765 return this.getGroupValue();
17771 //<script type="text/javascript">
17774 * Based Ext JS Library 1.1.1
17775 * Copyright(c) 2006-2007, Ext JS, LLC.
17781 * @class Roo.HtmlEditorCore
17782 * @extends Roo.Component
17783 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17785 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17788 Roo.HtmlEditorCore = function(config){
17791 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17796 * @event initialize
17797 * Fires when the editor is fully initialized (including the iframe)
17798 * @param {Roo.HtmlEditorCore} this
17803 * Fires when the editor is first receives the focus. Any insertion must wait
17804 * until after this event.
17805 * @param {Roo.HtmlEditorCore} this
17809 * @event beforesync
17810 * Fires before the textarea is updated with content from the editor iframe. Return false
17811 * to cancel the sync.
17812 * @param {Roo.HtmlEditorCore} this
17813 * @param {String} html
17817 * @event beforepush
17818 * Fires before the iframe editor is updated with content from the textarea. Return false
17819 * to cancel the push.
17820 * @param {Roo.HtmlEditorCore} this
17821 * @param {String} html
17826 * Fires when the textarea is updated with content from the editor iframe.
17827 * @param {Roo.HtmlEditorCore} this
17828 * @param {String} html
17833 * Fires when the iframe editor is updated with content from the textarea.
17834 * @param {Roo.HtmlEditorCore} this
17835 * @param {String} html
17840 * @event editorevent
17841 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17842 * @param {Roo.HtmlEditorCore} this
17848 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17850 // defaults : white / black...
17851 this.applyBlacklists();
17858 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17862 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17868 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17873 * @cfg {Number} height (in pixels)
17877 * @cfg {Number} width (in pixels)
17882 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17885 stylesheets: false,
17890 // private properties
17891 validationEvent : false,
17893 initialized : false,
17895 sourceEditMode : false,
17896 onFocus : Roo.emptyFn,
17898 hideMode:'offsets',
17902 // blacklist + whitelisted elements..
17909 * Protected method that will not generally be called directly. It
17910 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17911 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17913 getDocMarkup : function(){
17917 // inherit styels from page...??
17918 if (this.stylesheets === false) {
17920 Roo.get(document.head).select('style').each(function(node) {
17921 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17924 Roo.get(document.head).select('link').each(function(node) {
17925 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17928 } else if (!this.stylesheets.length) {
17930 st = '<style type="text/css">' +
17931 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17937 st += '<style type="text/css">' +
17938 'IMG { cursor: pointer } ' +
17942 return '<html><head>' + st +
17943 //<style type="text/css">' +
17944 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17946 ' </head><body class="roo-htmleditor-body"></body></html>';
17950 onRender : function(ct, position)
17953 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17954 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17957 this.el.dom.style.border = '0 none';
17958 this.el.dom.setAttribute('tabIndex', -1);
17959 this.el.addClass('x-hidden hide');
17963 if(Roo.isIE){ // fix IE 1px bogus margin
17964 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17968 this.frameId = Roo.id();
17972 var iframe = this.owner.wrap.createChild({
17974 cls: 'form-control', // bootstrap..
17976 name: this.frameId,
17977 frameBorder : 'no',
17978 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17983 this.iframe = iframe.dom;
17985 this.assignDocWin();
17987 this.doc.designMode = 'on';
17990 this.doc.write(this.getDocMarkup());
17994 var task = { // must defer to wait for browser to be ready
17996 //console.log("run task?" + this.doc.readyState);
17997 this.assignDocWin();
17998 if(this.doc.body || this.doc.readyState == 'complete'){
18000 this.doc.designMode="on";
18004 Roo.TaskMgr.stop(task);
18005 this.initEditor.defer(10, this);
18012 Roo.TaskMgr.start(task);
18017 onResize : function(w, h)
18019 Roo.log('resize: ' +w + ',' + h );
18020 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18024 if(typeof w == 'number'){
18026 this.iframe.style.width = w + 'px';
18028 if(typeof h == 'number'){
18030 this.iframe.style.height = h + 'px';
18032 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18039 * Toggles the editor between standard and source edit mode.
18040 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18042 toggleSourceEdit : function(sourceEditMode){
18044 this.sourceEditMode = sourceEditMode === true;
18046 if(this.sourceEditMode){
18048 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18051 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18052 //this.iframe.className = '';
18055 //this.setSize(this.owner.wrap.getSize());
18056 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18063 * Protected method that will not generally be called directly. If you need/want
18064 * custom HTML cleanup, this is the method you should override.
18065 * @param {String} html The HTML to be cleaned
18066 * return {String} The cleaned HTML
18068 cleanHtml : function(html){
18069 html = String(html);
18070 if(html.length > 5){
18071 if(Roo.isSafari){ // strip safari nonsense
18072 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18075 if(html == ' '){
18082 * HTML Editor -> Textarea
18083 * Protected method that will not generally be called directly. Syncs the contents
18084 * of the editor iframe with the textarea.
18086 syncValue : function(){
18087 if(this.initialized){
18088 var bd = (this.doc.body || this.doc.documentElement);
18089 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18090 var html = bd.innerHTML;
18092 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18093 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18095 html = '<div style="'+m[0]+'">' + html + '</div>';
18098 html = this.cleanHtml(html);
18099 // fix up the special chars.. normaly like back quotes in word...
18100 // however we do not want to do this with chinese..
18101 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18102 var cc = b.charCodeAt();
18104 (cc >= 0x4E00 && cc < 0xA000 ) ||
18105 (cc >= 0x3400 && cc < 0x4E00 ) ||
18106 (cc >= 0xf900 && cc < 0xfb00 )
18112 if(this.owner.fireEvent('beforesync', this, html) !== false){
18113 this.el.dom.value = html;
18114 this.owner.fireEvent('sync', this, html);
18120 * Protected method that will not generally be called directly. Pushes the value of the textarea
18121 * into the iframe editor.
18123 pushValue : function(){
18124 if(this.initialized){
18125 var v = this.el.dom.value.trim();
18127 // if(v.length < 1){
18131 if(this.owner.fireEvent('beforepush', this, v) !== false){
18132 var d = (this.doc.body || this.doc.documentElement);
18134 this.cleanUpPaste();
18135 this.el.dom.value = d.innerHTML;
18136 this.owner.fireEvent('push', this, v);
18142 deferFocus : function(){
18143 this.focus.defer(10, this);
18147 focus : function(){
18148 if(this.win && !this.sourceEditMode){
18155 assignDocWin: function()
18157 var iframe = this.iframe;
18160 this.doc = iframe.contentWindow.document;
18161 this.win = iframe.contentWindow;
18163 // if (!Roo.get(this.frameId)) {
18166 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18167 // this.win = Roo.get(this.frameId).dom.contentWindow;
18169 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18173 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18174 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18179 initEditor : function(){
18180 //console.log("INIT EDITOR");
18181 this.assignDocWin();
18185 this.doc.designMode="on";
18187 this.doc.write(this.getDocMarkup());
18190 var dbody = (this.doc.body || this.doc.documentElement);
18191 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18192 // this copies styles from the containing element into thsi one..
18193 // not sure why we need all of this..
18194 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18196 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18197 //ss['background-attachment'] = 'fixed'; // w3c
18198 dbody.bgProperties = 'fixed'; // ie
18199 //Roo.DomHelper.applyStyles(dbody, ss);
18200 Roo.EventManager.on(this.doc, {
18201 //'mousedown': this.onEditorEvent,
18202 'mouseup': this.onEditorEvent,
18203 'dblclick': this.onEditorEvent,
18204 'click': this.onEditorEvent,
18205 'keyup': this.onEditorEvent,
18210 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18212 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18213 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18215 this.initialized = true;
18217 this.owner.fireEvent('initialize', this);
18222 onDestroy : function(){
18228 //for (var i =0; i < this.toolbars.length;i++) {
18229 // // fixme - ask toolbars for heights?
18230 // this.toolbars[i].onDestroy();
18233 //this.wrap.dom.innerHTML = '';
18234 //this.wrap.remove();
18239 onFirstFocus : function(){
18241 this.assignDocWin();
18244 this.activated = true;
18247 if(Roo.isGecko){ // prevent silly gecko errors
18249 var s = this.win.getSelection();
18250 if(!s.focusNode || s.focusNode.nodeType != 3){
18251 var r = s.getRangeAt(0);
18252 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18257 this.execCmd('useCSS', true);
18258 this.execCmd('styleWithCSS', false);
18261 this.owner.fireEvent('activate', this);
18265 adjustFont: function(btn){
18266 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18267 //if(Roo.isSafari){ // safari
18270 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18271 if(Roo.isSafari){ // safari
18272 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18273 v = (v < 10) ? 10 : v;
18274 v = (v > 48) ? 48 : v;
18275 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18280 v = Math.max(1, v+adjust);
18282 this.execCmd('FontSize', v );
18285 onEditorEvent : function(e){
18286 this.owner.fireEvent('editorevent', this, e);
18287 // this.updateToolbar();
18288 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18291 insertTag : function(tg)
18293 // could be a bit smarter... -> wrap the current selected tRoo..
18294 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18296 range = this.createRange(this.getSelection());
18297 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18298 wrappingNode.appendChild(range.extractContents());
18299 range.insertNode(wrappingNode);
18306 this.execCmd("formatblock", tg);
18310 insertText : function(txt)
18314 var range = this.createRange();
18315 range.deleteContents();
18316 //alert(Sender.getAttribute('label'));
18318 range.insertNode(this.doc.createTextNode(txt));
18324 * Executes a Midas editor command on the editor document and performs necessary focus and
18325 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18326 * @param {String} cmd The Midas command
18327 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18329 relayCmd : function(cmd, value){
18331 this.execCmd(cmd, value);
18332 this.owner.fireEvent('editorevent', this);
18333 //this.updateToolbar();
18334 this.owner.deferFocus();
18338 * Executes a Midas editor command directly on the editor document.
18339 * For visual commands, you should use {@link #relayCmd} instead.
18340 * <b>This should only be called after the editor is initialized.</b>
18341 * @param {String} cmd The Midas command
18342 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18344 execCmd : function(cmd, value){
18345 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18352 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18354 * @param {String} text | dom node..
18356 insertAtCursor : function(text)
18361 if(!this.activated){
18367 var r = this.doc.selection.createRange();
18378 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18382 // from jquery ui (MIT licenced)
18384 var win = this.win;
18386 if (win.getSelection && win.getSelection().getRangeAt) {
18387 range = win.getSelection().getRangeAt(0);
18388 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18389 range.insertNode(node);
18390 } else if (win.document.selection && win.document.selection.createRange) {
18391 // no firefox support
18392 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18393 win.document.selection.createRange().pasteHTML(txt);
18395 // no firefox support
18396 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18397 this.execCmd('InsertHTML', txt);
18406 mozKeyPress : function(e){
18408 var c = e.getCharCode(), cmd;
18411 c = String.fromCharCode(c).toLowerCase();
18425 this.cleanUpPaste.defer(100, this);
18433 e.preventDefault();
18441 fixKeys : function(){ // load time branching for fastest keydown performance
18443 return function(e){
18444 var k = e.getKey(), r;
18447 r = this.doc.selection.createRange();
18450 r.pasteHTML('    ');
18457 r = this.doc.selection.createRange();
18459 var target = r.parentElement();
18460 if(!target || target.tagName.toLowerCase() != 'li'){
18462 r.pasteHTML('<br />');
18468 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18469 this.cleanUpPaste.defer(100, this);
18475 }else if(Roo.isOpera){
18476 return function(e){
18477 var k = e.getKey();
18481 this.execCmd('InsertHTML','    ');
18484 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18485 this.cleanUpPaste.defer(100, this);
18490 }else if(Roo.isSafari){
18491 return function(e){
18492 var k = e.getKey();
18496 this.execCmd('InsertText','\t');
18500 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18501 this.cleanUpPaste.defer(100, this);
18509 getAllAncestors: function()
18511 var p = this.getSelectedNode();
18514 a.push(p); // push blank onto stack..
18515 p = this.getParentElement();
18519 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18523 a.push(this.doc.body);
18527 lastSelNode : false,
18530 getSelection : function()
18532 this.assignDocWin();
18533 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18536 getSelectedNode: function()
18538 // this may only work on Gecko!!!
18540 // should we cache this!!!!
18545 var range = this.createRange(this.getSelection()).cloneRange();
18548 var parent = range.parentElement();
18550 var testRange = range.duplicate();
18551 testRange.moveToElementText(parent);
18552 if (testRange.inRange(range)) {
18555 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18558 parent = parent.parentElement;
18563 // is ancestor a text element.
18564 var ac = range.commonAncestorContainer;
18565 if (ac.nodeType == 3) {
18566 ac = ac.parentNode;
18569 var ar = ac.childNodes;
18572 var other_nodes = [];
18573 var has_other_nodes = false;
18574 for (var i=0;i<ar.length;i++) {
18575 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18578 // fullly contained node.
18580 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18585 // probably selected..
18586 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18587 other_nodes.push(ar[i]);
18591 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18596 has_other_nodes = true;
18598 if (!nodes.length && other_nodes.length) {
18599 nodes= other_nodes;
18601 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18607 createRange: function(sel)
18609 // this has strange effects when using with
18610 // top toolbar - not sure if it's a great idea.
18611 //this.editor.contentWindow.focus();
18612 if (typeof sel != "undefined") {
18614 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18616 return this.doc.createRange();
18619 return this.doc.createRange();
18622 getParentElement: function()
18625 this.assignDocWin();
18626 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18628 var range = this.createRange(sel);
18631 var p = range.commonAncestorContainer;
18632 while (p.nodeType == 3) { // text node
18643 * Range intersection.. the hard stuff...
18647 * [ -- selected range --- ]
18651 * if end is before start or hits it. fail.
18652 * if start is after end or hits it fail.
18654 * if either hits (but other is outside. - then it's not
18660 // @see http://www.thismuchiknow.co.uk/?p=64.
18661 rangeIntersectsNode : function(range, node)
18663 var nodeRange = node.ownerDocument.createRange();
18665 nodeRange.selectNode(node);
18667 nodeRange.selectNodeContents(node);
18670 var rangeStartRange = range.cloneRange();
18671 rangeStartRange.collapse(true);
18673 var rangeEndRange = range.cloneRange();
18674 rangeEndRange.collapse(false);
18676 var nodeStartRange = nodeRange.cloneRange();
18677 nodeStartRange.collapse(true);
18679 var nodeEndRange = nodeRange.cloneRange();
18680 nodeEndRange.collapse(false);
18682 return rangeStartRange.compareBoundaryPoints(
18683 Range.START_TO_START, nodeEndRange) == -1 &&
18684 rangeEndRange.compareBoundaryPoints(
18685 Range.START_TO_START, nodeStartRange) == 1;
18689 rangeCompareNode : function(range, node)
18691 var nodeRange = node.ownerDocument.createRange();
18693 nodeRange.selectNode(node);
18695 nodeRange.selectNodeContents(node);
18699 range.collapse(true);
18701 nodeRange.collapse(true);
18703 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18704 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18706 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18708 var nodeIsBefore = ss == 1;
18709 var nodeIsAfter = ee == -1;
18711 if (nodeIsBefore && nodeIsAfter)
18713 if (!nodeIsBefore && nodeIsAfter)
18714 return 1; //right trailed.
18716 if (nodeIsBefore && !nodeIsAfter)
18717 return 2; // left trailed.
18722 // private? - in a new class?
18723 cleanUpPaste : function()
18725 // cleans up the whole document..
18726 Roo.log('cleanuppaste');
18728 this.cleanUpChildren(this.doc.body);
18729 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18730 if (clean != this.doc.body.innerHTML) {
18731 this.doc.body.innerHTML = clean;
18736 cleanWordChars : function(input) {// change the chars to hex code
18737 var he = Roo.HtmlEditorCore;
18739 var output = input;
18740 Roo.each(he.swapCodes, function(sw) {
18741 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18743 output = output.replace(swapper, sw[1]);
18750 cleanUpChildren : function (n)
18752 if (!n.childNodes.length) {
18755 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18756 this.cleanUpChild(n.childNodes[i]);
18763 cleanUpChild : function (node)
18766 //console.log(node);
18767 if (node.nodeName == "#text") {
18768 // clean up silly Windows -- stuff?
18771 if (node.nodeName == "#comment") {
18772 node.parentNode.removeChild(node);
18773 // clean up silly Windows -- stuff?
18776 var lcname = node.tagName.toLowerCase();
18777 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18778 // whitelist of tags..
18780 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18782 node.parentNode.removeChild(node);
18787 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18789 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18790 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18792 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18793 // remove_keep_children = true;
18796 if (remove_keep_children) {
18797 this.cleanUpChildren(node);
18798 // inserts everything just before this node...
18799 while (node.childNodes.length) {
18800 var cn = node.childNodes[0];
18801 node.removeChild(cn);
18802 node.parentNode.insertBefore(cn, node);
18804 node.parentNode.removeChild(node);
18808 if (!node.attributes || !node.attributes.length) {
18809 this.cleanUpChildren(node);
18813 function cleanAttr(n,v)
18816 if (v.match(/^\./) || v.match(/^\//)) {
18819 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18822 if (v.match(/^#/)) {
18825 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18826 node.removeAttribute(n);
18830 var cwhite = this.cwhite;
18831 var cblack = this.cblack;
18833 function cleanStyle(n,v)
18835 if (v.match(/expression/)) { //XSS?? should we even bother..
18836 node.removeAttribute(n);
18840 var parts = v.split(/;/);
18843 Roo.each(parts, function(p) {
18844 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18848 var l = p.split(':').shift().replace(/\s+/g,'');
18849 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18851 if ( cwhite.length && cblack.indexOf(l) > -1) {
18852 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18853 //node.removeAttribute(n);
18857 // only allow 'c whitelisted system attributes'
18858 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18859 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18860 //node.removeAttribute(n);
18870 if (clean.length) {
18871 node.setAttribute(n, clean.join(';'));
18873 node.removeAttribute(n);
18879 for (var i = node.attributes.length-1; i > -1 ; i--) {
18880 var a = node.attributes[i];
18883 if (a.name.toLowerCase().substr(0,2)=='on') {
18884 node.removeAttribute(a.name);
18887 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18888 node.removeAttribute(a.name);
18891 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18892 cleanAttr(a.name,a.value); // fixme..
18895 if (a.name == 'style') {
18896 cleanStyle(a.name,a.value);
18899 /// clean up MS crap..
18900 // tecnically this should be a list of valid class'es..
18903 if (a.name == 'class') {
18904 if (a.value.match(/^Mso/)) {
18905 node.className = '';
18908 if (a.value.match(/body/)) {
18909 node.className = '';
18920 this.cleanUpChildren(node);
18925 * Clean up MS wordisms...
18927 cleanWord : function(node)
18930 var cleanWordChildren = function()
18932 if (!node.childNodes.length) {
18935 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18936 _t.cleanWord(node.childNodes[i]);
18942 this.cleanWord(this.doc.body);
18945 if (node.nodeName == "#text") {
18946 // clean up silly Windows -- stuff?
18949 if (node.nodeName == "#comment") {
18950 node.parentNode.removeChild(node);
18951 // clean up silly Windows -- stuff?
18955 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18956 node.parentNode.removeChild(node);
18960 // remove - but keep children..
18961 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18962 while (node.childNodes.length) {
18963 var cn = node.childNodes[0];
18964 node.removeChild(cn);
18965 node.parentNode.insertBefore(cn, node);
18967 node.parentNode.removeChild(node);
18968 cleanWordChildren();
18972 if (node.className.length) {
18974 var cn = node.className.split(/\W+/);
18976 Roo.each(cn, function(cls) {
18977 if (cls.match(/Mso[a-zA-Z]+/)) {
18982 node.className = cna.length ? cna.join(' ') : '';
18984 node.removeAttribute("class");
18988 if (node.hasAttribute("lang")) {
18989 node.removeAttribute("lang");
18992 if (node.hasAttribute("style")) {
18994 var styles = node.getAttribute("style").split(";");
18996 Roo.each(styles, function(s) {
18997 if (!s.match(/:/)) {
19000 var kv = s.split(":");
19001 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19004 // what ever is left... we allow.
19007 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19008 if (!nstyle.length) {
19009 node.removeAttribute('style');
19013 cleanWordChildren();
19017 domToHTML : function(currentElement, depth, nopadtext) {
19019 depth = depth || 0;
19020 nopadtext = nopadtext || false;
19022 if (!currentElement) {
19023 return this.domToHTML(this.doc.body);
19026 //Roo.log(currentElement);
19028 var allText = false;
19029 var nodeName = currentElement.nodeName;
19030 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19032 if (nodeName == '#text') {
19034 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19039 if (nodeName != 'BODY') {
19042 // Prints the node tagName, such as <A>, <IMG>, etc
19045 for(i = 0; i < currentElement.attributes.length;i++) {
19047 var aname = currentElement.attributes.item(i).name;
19048 if (!currentElement.attributes.item(i).value.length) {
19051 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19054 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19063 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19066 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19071 // Traverse the tree
19073 var currentElementChild = currentElement.childNodes.item(i);
19074 var allText = true;
19075 var innerHTML = '';
19077 while (currentElementChild) {
19078 // Formatting code (indent the tree so it looks nice on the screen)
19079 var nopad = nopadtext;
19080 if (lastnode == 'SPAN') {
19084 if (currentElementChild.nodeName == '#text') {
19085 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19086 toadd = nopadtext ? toadd : toadd.trim();
19087 if (!nopad && toadd.length > 80) {
19088 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19090 innerHTML += toadd;
19093 currentElementChild = currentElement.childNodes.item(i);
19099 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19101 // Recursively traverse the tree structure of the child node
19102 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19103 lastnode = currentElementChild.nodeName;
19105 currentElementChild=currentElement.childNodes.item(i);
19111 // The remaining code is mostly for formatting the tree
19112 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19117 ret+= "</"+tagName+">";
19123 applyBlacklists : function()
19125 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19126 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19130 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19131 if (b.indexOf(tag) > -1) {
19134 this.white.push(tag);
19138 Roo.each(w, function(tag) {
19139 if (b.indexOf(tag) > -1) {
19142 if (this.white.indexOf(tag) > -1) {
19145 this.white.push(tag);
19150 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19151 if (w.indexOf(tag) > -1) {
19154 this.black.push(tag);
19158 Roo.each(b, function(tag) {
19159 if (w.indexOf(tag) > -1) {
19162 if (this.black.indexOf(tag) > -1) {
19165 this.black.push(tag);
19170 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19171 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19175 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19176 if (b.indexOf(tag) > -1) {
19179 this.cwhite.push(tag);
19183 Roo.each(w, function(tag) {
19184 if (b.indexOf(tag) > -1) {
19187 if (this.cwhite.indexOf(tag) > -1) {
19190 this.cwhite.push(tag);
19195 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19196 if (w.indexOf(tag) > -1) {
19199 this.cblack.push(tag);
19203 Roo.each(b, function(tag) {
19204 if (w.indexOf(tag) > -1) {
19207 if (this.cblack.indexOf(tag) > -1) {
19210 this.cblack.push(tag);
19215 setStylesheets : function(stylesheets)
19217 if(typeof(stylesheets) == 'string'){
19218 Roo.get(this.iframe.contentDocument.head).createChild({
19220 rel : 'stylesheet',
19229 Roo.each(stylesheets, function(s) {
19234 Roo.get(_this.iframe.contentDocument.head).createChild({
19236 rel : 'stylesheet',
19245 removeStylesheets : function()
19249 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19254 // hide stuff that is not compatible
19268 * @event specialkey
19272 * @cfg {String} fieldClass @hide
19275 * @cfg {String} focusClass @hide
19278 * @cfg {String} autoCreate @hide
19281 * @cfg {String} inputType @hide
19284 * @cfg {String} invalidClass @hide
19287 * @cfg {String} invalidText @hide
19290 * @cfg {String} msgFx @hide
19293 * @cfg {String} validateOnBlur @hide
19297 Roo.HtmlEditorCore.white = [
19298 'area', 'br', 'img', 'input', 'hr', 'wbr',
19300 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19301 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19302 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19303 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19304 'table', 'ul', 'xmp',
19306 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19309 'dir', 'menu', 'ol', 'ul', 'dl',
19315 Roo.HtmlEditorCore.black = [
19316 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19318 'base', 'basefont', 'bgsound', 'blink', 'body',
19319 'frame', 'frameset', 'head', 'html', 'ilayer',
19320 'iframe', 'layer', 'link', 'meta', 'object',
19321 'script', 'style' ,'title', 'xml' // clean later..
19323 Roo.HtmlEditorCore.clean = [
19324 'script', 'style', 'title', 'xml'
19326 Roo.HtmlEditorCore.remove = [
19331 Roo.HtmlEditorCore.ablack = [
19335 Roo.HtmlEditorCore.aclean = [
19336 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19340 Roo.HtmlEditorCore.pwhite= [
19341 'http', 'https', 'mailto'
19344 // white listed style attributes.
19345 Roo.HtmlEditorCore.cwhite= [
19346 // 'text-align', /// default is to allow most things..
19352 // black listed style attributes.
19353 Roo.HtmlEditorCore.cblack= [
19354 // 'font-size' -- this can be set by the project
19358 Roo.HtmlEditorCore.swapCodes =[
19377 * @class Roo.bootstrap.HtmlEditor
19378 * @extends Roo.bootstrap.TextArea
19379 * Bootstrap HtmlEditor class
19382 * Create a new HtmlEditor
19383 * @param {Object} config The config object
19386 Roo.bootstrap.HtmlEditor = function(config){
19387 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19388 if (!this.toolbars) {
19389 this.toolbars = [];
19391 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19394 * @event initialize
19395 * Fires when the editor is fully initialized (including the iframe)
19396 * @param {HtmlEditor} this
19401 * Fires when the editor is first receives the focus. Any insertion must wait
19402 * until after this event.
19403 * @param {HtmlEditor} this
19407 * @event beforesync
19408 * Fires before the textarea is updated with content from the editor iframe. Return false
19409 * to cancel the sync.
19410 * @param {HtmlEditor} this
19411 * @param {String} html
19415 * @event beforepush
19416 * Fires before the iframe editor is updated with content from the textarea. Return false
19417 * to cancel the push.
19418 * @param {HtmlEditor} this
19419 * @param {String} html
19424 * Fires when the textarea is updated with content from the editor iframe.
19425 * @param {HtmlEditor} this
19426 * @param {String} html
19431 * Fires when the iframe editor is updated with content from the textarea.
19432 * @param {HtmlEditor} this
19433 * @param {String} html
19437 * @event editmodechange
19438 * Fires when the editor switches edit modes
19439 * @param {HtmlEditor} this
19440 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19442 editmodechange: true,
19444 * @event editorevent
19445 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19446 * @param {HtmlEditor} this
19450 * @event firstfocus
19451 * Fires when on first focus - needed by toolbars..
19452 * @param {HtmlEditor} this
19457 * Auto save the htmlEditor value as a file into Events
19458 * @param {HtmlEditor} this
19462 * @event savedpreview
19463 * preview the saved version of htmlEditor
19464 * @param {HtmlEditor} this
19471 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19475 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19480 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19485 * @cfg {Number} height (in pixels)
19489 * @cfg {Number} width (in pixels)
19494 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19497 stylesheets: false,
19502 // private properties
19503 validationEvent : false,
19505 initialized : false,
19508 onFocus : Roo.emptyFn,
19510 hideMode:'offsets',
19513 tbContainer : false,
19515 toolbarContainer :function() {
19516 return this.wrap.select('.x-html-editor-tb',true).first();
19520 * Protected method that will not generally be called directly. It
19521 * is called when the editor creates its toolbar. Override this method if you need to
19522 * add custom toolbar buttons.
19523 * @param {HtmlEditor} editor
19525 createToolbar : function(){
19527 Roo.log("create toolbars");
19529 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19530 this.toolbars[0].render(this.toolbarContainer());
19534 // if (!editor.toolbars || !editor.toolbars.length) {
19535 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19538 // for (var i =0 ; i < editor.toolbars.length;i++) {
19539 // editor.toolbars[i] = Roo.factory(
19540 // typeof(editor.toolbars[i]) == 'string' ?
19541 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19542 // Roo.bootstrap.HtmlEditor);
19543 // editor.toolbars[i].init(editor);
19549 onRender : function(ct, position)
19551 // Roo.log("Call onRender: " + this.xtype);
19553 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19555 this.wrap = this.inputEl().wrap({
19556 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19559 this.editorcore.onRender(ct, position);
19561 if (this.resizable) {
19562 this.resizeEl = new Roo.Resizable(this.wrap, {
19566 minHeight : this.height,
19567 height: this.height,
19568 handles : this.resizable,
19571 resize : function(r, w, h) {
19572 _t.onResize(w,h); // -something
19578 this.createToolbar(this);
19581 if(!this.width && this.resizable){
19582 this.setSize(this.wrap.getSize());
19584 if (this.resizeEl) {
19585 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19586 // should trigger onReize..
19592 onResize : function(w, h)
19594 Roo.log('resize: ' +w + ',' + h );
19595 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19599 if(this.inputEl() ){
19600 if(typeof w == 'number'){
19601 var aw = w - this.wrap.getFrameWidth('lr');
19602 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19605 if(typeof h == 'number'){
19606 var tbh = -11; // fixme it needs to tool bar size!
19607 for (var i =0; i < this.toolbars.length;i++) {
19608 // fixme - ask toolbars for heights?
19609 tbh += this.toolbars[i].el.getHeight();
19610 //if (this.toolbars[i].footer) {
19611 // tbh += this.toolbars[i].footer.el.getHeight();
19619 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19620 ah -= 5; // knock a few pixes off for look..
19621 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19625 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19626 this.editorcore.onResize(ew,eh);
19631 * Toggles the editor between standard and source edit mode.
19632 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19634 toggleSourceEdit : function(sourceEditMode)
19636 this.editorcore.toggleSourceEdit(sourceEditMode);
19638 if(this.editorcore.sourceEditMode){
19639 Roo.log('editor - showing textarea');
19642 // Roo.log(this.syncValue());
19644 this.inputEl().removeClass(['hide', 'x-hidden']);
19645 this.inputEl().dom.removeAttribute('tabIndex');
19646 this.inputEl().focus();
19648 Roo.log('editor - hiding textarea');
19650 // Roo.log(this.pushValue());
19653 this.inputEl().addClass(['hide', 'x-hidden']);
19654 this.inputEl().dom.setAttribute('tabIndex', -1);
19655 //this.deferFocus();
19658 if(this.resizable){
19659 this.setSize(this.wrap.getSize());
19662 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19665 // private (for BoxComponent)
19666 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19668 // private (for BoxComponent)
19669 getResizeEl : function(){
19673 // private (for BoxComponent)
19674 getPositionEl : function(){
19679 initEvents : function(){
19680 this.originalValue = this.getValue();
19684 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19687 // markInvalid : Roo.emptyFn,
19689 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19692 // clearInvalid : Roo.emptyFn,
19694 setValue : function(v){
19695 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19696 this.editorcore.pushValue();
19701 deferFocus : function(){
19702 this.focus.defer(10, this);
19706 focus : function(){
19707 this.editorcore.focus();
19713 onDestroy : function(){
19719 for (var i =0; i < this.toolbars.length;i++) {
19720 // fixme - ask toolbars for heights?
19721 this.toolbars[i].onDestroy();
19724 this.wrap.dom.innerHTML = '';
19725 this.wrap.remove();
19730 onFirstFocus : function(){
19731 //Roo.log("onFirstFocus");
19732 this.editorcore.onFirstFocus();
19733 for (var i =0; i < this.toolbars.length;i++) {
19734 this.toolbars[i].onFirstFocus();
19740 syncValue : function()
19742 this.editorcore.syncValue();
19745 pushValue : function()
19747 this.editorcore.pushValue();
19751 // hide stuff that is not compatible
19765 * @event specialkey
19769 * @cfg {String} fieldClass @hide
19772 * @cfg {String} focusClass @hide
19775 * @cfg {String} autoCreate @hide
19778 * @cfg {String} inputType @hide
19781 * @cfg {String} invalidClass @hide
19784 * @cfg {String} invalidText @hide
19787 * @cfg {String} msgFx @hide
19790 * @cfg {String} validateOnBlur @hide
19799 Roo.namespace('Roo.bootstrap.htmleditor');
19801 * @class Roo.bootstrap.HtmlEditorToolbar1
19806 new Roo.bootstrap.HtmlEditor({
19809 new Roo.bootstrap.HtmlEditorToolbar1({
19810 disable : { fonts: 1 , format: 1, ..., ... , ...],
19816 * @cfg {Object} disable List of elements to disable..
19817 * @cfg {Array} btns List of additional buttons.
19821 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19824 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19827 Roo.apply(this, config);
19829 // default disabled, based on 'good practice'..
19830 this.disable = this.disable || {};
19831 Roo.applyIf(this.disable, {
19834 specialElements : true
19836 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19838 this.editor = config.editor;
19839 this.editorcore = config.editor.editorcore;
19841 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19843 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19844 // dont call parent... till later.
19846 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19851 editorcore : false,
19856 "h1","h2","h3","h4","h5","h6",
19858 "abbr", "acronym", "address", "cite", "samp", "var",
19862 onRender : function(ct, position)
19864 // Roo.log("Call onRender: " + this.xtype);
19866 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19868 this.el.dom.style.marginBottom = '0';
19870 var editorcore = this.editorcore;
19871 var editor= this.editor;
19874 var btn = function(id,cmd , toggle, handler){
19876 var event = toggle ? 'toggle' : 'click';
19881 xns: Roo.bootstrap,
19884 enableToggle:toggle !== false,
19886 pressed : toggle ? false : null,
19889 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19890 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19899 xns: Roo.bootstrap,
19900 glyphicon : 'font',
19904 xns: Roo.bootstrap,
19908 Roo.each(this.formats, function(f) {
19909 style.menu.items.push({
19911 xns: Roo.bootstrap,
19912 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19917 editorcore.insertTag(this.tagname);
19924 children.push(style);
19927 btn('bold',false,true);
19928 btn('italic',false,true);
19929 btn('align-left', 'justifyleft',true);
19930 btn('align-center', 'justifycenter',true);
19931 btn('align-right' , 'justifyright',true);
19932 btn('link', false, false, function(btn) {
19933 //Roo.log("create link?");
19934 var url = prompt(this.createLinkText, this.defaultLinkValue);
19935 if(url && url != 'http:/'+'/'){
19936 this.editorcore.relayCmd('createlink', url);
19939 btn('list','insertunorderedlist',true);
19940 btn('pencil', false,true, function(btn){
19943 this.toggleSourceEdit(btn.pressed);
19949 xns: Roo.bootstrap,
19954 xns: Roo.bootstrap,
19959 cog.menu.items.push({
19961 xns: Roo.bootstrap,
19962 html : Clean styles,
19967 editorcore.insertTag(this.tagname);
19976 this.xtype = 'NavSimplebar';
19978 for(var i=0;i< children.length;i++) {
19980 this.buttons.add(this.addxtypeChild(children[i]));
19984 editor.on('editorevent', this.updateToolbar, this);
19986 onBtnClick : function(id)
19988 this.editorcore.relayCmd(id);
19989 this.editorcore.focus();
19993 * Protected method that will not generally be called directly. It triggers
19994 * a toolbar update by reading the markup state of the current selection in the editor.
19996 updateToolbar: function(){
19998 if(!this.editorcore.activated){
19999 this.editor.onFirstFocus(); // is this neeed?
20003 var btns = this.buttons;
20004 var doc = this.editorcore.doc;
20005 btns.get('bold').setActive(doc.queryCommandState('bold'));
20006 btns.get('italic').setActive(doc.queryCommandState('italic'));
20007 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20009 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20010 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20011 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20013 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20014 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20017 var ans = this.editorcore.getAllAncestors();
20018 if (this.formatCombo) {
20021 var store = this.formatCombo.store;
20022 this.formatCombo.setValue("");
20023 for (var i =0; i < ans.length;i++) {
20024 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20026 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20034 // hides menus... - so this cant be on a menu...
20035 Roo.bootstrap.MenuMgr.hideAll();
20037 Roo.bootstrap.MenuMgr.hideAll();
20038 //this.editorsyncValue();
20040 onFirstFocus: function() {
20041 this.buttons.each(function(item){
20045 toggleSourceEdit : function(sourceEditMode){
20048 if(sourceEditMode){
20049 Roo.log("disabling buttons");
20050 this.buttons.each( function(item){
20051 if(item.cmd != 'pencil'){
20057 Roo.log("enabling buttons");
20058 if(this.editorcore.initialized){
20059 this.buttons.each( function(item){
20065 Roo.log("calling toggole on editor");
20066 // tell the editor that it's been pressed..
20067 this.editor.toggleSourceEdit(sourceEditMode);
20077 * @class Roo.bootstrap.Table.AbstractSelectionModel
20078 * @extends Roo.util.Observable
20079 * Abstract base class for grid SelectionModels. It provides the interface that should be
20080 * implemented by descendant classes. This class should not be directly instantiated.
20083 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20084 this.locked = false;
20085 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20089 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20090 /** @ignore Called by the grid automatically. Do not call directly. */
20091 init : function(grid){
20097 * Locks the selections.
20100 this.locked = true;
20104 * Unlocks the selections.
20106 unlock : function(){
20107 this.locked = false;
20111 * Returns true if the selections are locked.
20112 * @return {Boolean}
20114 isLocked : function(){
20115 return this.locked;
20119 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20120 * @class Roo.bootstrap.Table.RowSelectionModel
20121 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20122 * It supports multiple selections and keyboard selection/navigation.
20124 * @param {Object} config
20127 Roo.bootstrap.Table.RowSelectionModel = function(config){
20128 Roo.apply(this, config);
20129 this.selections = new Roo.util.MixedCollection(false, function(o){
20134 this.lastActive = false;
20138 * @event selectionchange
20139 * Fires when the selection changes
20140 * @param {SelectionModel} this
20142 "selectionchange" : true,
20144 * @event afterselectionchange
20145 * Fires after the selection changes (eg. by key press or clicking)
20146 * @param {SelectionModel} this
20148 "afterselectionchange" : true,
20150 * @event beforerowselect
20151 * Fires when a row is selected being selected, return false to cancel.
20152 * @param {SelectionModel} this
20153 * @param {Number} rowIndex The selected index
20154 * @param {Boolean} keepExisting False if other selections will be cleared
20156 "beforerowselect" : true,
20159 * Fires when a row is selected.
20160 * @param {SelectionModel} this
20161 * @param {Number} rowIndex The selected index
20162 * @param {Roo.data.Record} r The record
20164 "rowselect" : true,
20166 * @event rowdeselect
20167 * Fires when a row is deselected.
20168 * @param {SelectionModel} this
20169 * @param {Number} rowIndex The selected index
20171 "rowdeselect" : true
20173 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20174 this.locked = false;
20177 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20179 * @cfg {Boolean} singleSelect
20180 * True to allow selection of only one row at a time (defaults to false)
20182 singleSelect : false,
20185 initEvents : function(){
20187 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20188 this.grid.on("mousedown", this.handleMouseDown, this);
20189 }else{ // allow click to work like normal
20190 this.grid.on("rowclick", this.handleDragableRowClick, this);
20193 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20194 "up" : function(e){
20196 this.selectPrevious(e.shiftKey);
20197 }else if(this.last !== false && this.lastActive !== false){
20198 var last = this.last;
20199 this.selectRange(this.last, this.lastActive-1);
20200 this.grid.getView().focusRow(this.lastActive);
20201 if(last !== false){
20205 this.selectFirstRow();
20207 this.fireEvent("afterselectionchange", this);
20209 "down" : function(e){
20211 this.selectNext(e.shiftKey);
20212 }else if(this.last !== false && this.lastActive !== false){
20213 var last = this.last;
20214 this.selectRange(this.last, this.lastActive+1);
20215 this.grid.getView().focusRow(this.lastActive);
20216 if(last !== false){
20220 this.selectFirstRow();
20222 this.fireEvent("afterselectionchange", this);
20227 var view = this.grid.view;
20228 view.on("refresh", this.onRefresh, this);
20229 view.on("rowupdated", this.onRowUpdated, this);
20230 view.on("rowremoved", this.onRemove, this);
20234 onRefresh : function(){
20235 var ds = this.grid.dataSource, i, v = this.grid.view;
20236 var s = this.selections;
20237 s.each(function(r){
20238 if((i = ds.indexOfId(r.id)) != -1){
20247 onRemove : function(v, index, r){
20248 this.selections.remove(r);
20252 onRowUpdated : function(v, index, r){
20253 if(this.isSelected(r)){
20254 v.onRowSelect(index);
20260 * @param {Array} records The records to select
20261 * @param {Boolean} keepExisting (optional) True to keep existing selections
20263 selectRecords : function(records, keepExisting){
20265 this.clearSelections();
20267 var ds = this.grid.dataSource;
20268 for(var i = 0, len = records.length; i < len; i++){
20269 this.selectRow(ds.indexOf(records[i]), true);
20274 * Gets the number of selected rows.
20277 getCount : function(){
20278 return this.selections.length;
20282 * Selects the first row in the grid.
20284 selectFirstRow : function(){
20289 * Select the last row.
20290 * @param {Boolean} keepExisting (optional) True to keep existing selections
20292 selectLastRow : function(keepExisting){
20293 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20297 * Selects the row immediately following the last selected row.
20298 * @param {Boolean} keepExisting (optional) True to keep existing selections
20300 selectNext : function(keepExisting){
20301 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20302 this.selectRow(this.last+1, keepExisting);
20303 this.grid.getView().focusRow(this.last);
20308 * Selects the row that precedes the last selected row.
20309 * @param {Boolean} keepExisting (optional) True to keep existing selections
20311 selectPrevious : function(keepExisting){
20313 this.selectRow(this.last-1, keepExisting);
20314 this.grid.getView().focusRow(this.last);
20319 * Returns the selected records
20320 * @return {Array} Array of selected records
20322 getSelections : function(){
20323 return [].concat(this.selections.items);
20327 * Returns the first selected record.
20330 getSelected : function(){
20331 return this.selections.itemAt(0);
20336 * Clears all selections.
20338 clearSelections : function(fast){
20339 if(this.locked) return;
20341 var ds = this.grid.dataSource;
20342 var s = this.selections;
20343 s.each(function(r){
20344 this.deselectRow(ds.indexOfId(r.id));
20348 this.selections.clear();
20355 * Selects all rows.
20357 selectAll : function(){
20358 if(this.locked) return;
20359 this.selections.clear();
20360 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20361 this.selectRow(i, true);
20366 * Returns True if there is a selection.
20367 * @return {Boolean}
20369 hasSelection : function(){
20370 return this.selections.length > 0;
20374 * Returns True if the specified row is selected.
20375 * @param {Number/Record} record The record or index of the record to check
20376 * @return {Boolean}
20378 isSelected : function(index){
20379 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20380 return (r && this.selections.key(r.id) ? true : false);
20384 * Returns True if the specified record id is selected.
20385 * @param {String} id The id of record to check
20386 * @return {Boolean}
20388 isIdSelected : function(id){
20389 return (this.selections.key(id) ? true : false);
20393 handleMouseDown : function(e, t){
20394 var view = this.grid.getView(), rowIndex;
20395 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20398 if(e.shiftKey && this.last !== false){
20399 var last = this.last;
20400 this.selectRange(last, rowIndex, e.ctrlKey);
20401 this.last = last; // reset the last
20402 view.focusRow(rowIndex);
20404 var isSelected = this.isSelected(rowIndex);
20405 if(e.button !== 0 && isSelected){
20406 view.focusRow(rowIndex);
20407 }else if(e.ctrlKey && isSelected){
20408 this.deselectRow(rowIndex);
20409 }else if(!isSelected){
20410 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20411 view.focusRow(rowIndex);
20414 this.fireEvent("afterselectionchange", this);
20417 handleDragableRowClick : function(grid, rowIndex, e)
20419 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20420 this.selectRow(rowIndex, false);
20421 grid.view.focusRow(rowIndex);
20422 this.fireEvent("afterselectionchange", this);
20427 * Selects multiple rows.
20428 * @param {Array} rows Array of the indexes of the row to select
20429 * @param {Boolean} keepExisting (optional) True to keep existing selections
20431 selectRows : function(rows, keepExisting){
20433 this.clearSelections();
20435 for(var i = 0, len = rows.length; i < len; i++){
20436 this.selectRow(rows[i], true);
20441 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20442 * @param {Number} startRow The index of the first row in the range
20443 * @param {Number} endRow The index of the last row in the range
20444 * @param {Boolean} keepExisting (optional) True to retain existing selections
20446 selectRange : function(startRow, endRow, keepExisting){
20447 if(this.locked) return;
20449 this.clearSelections();
20451 if(startRow <= endRow){
20452 for(var i = startRow; i <= endRow; i++){
20453 this.selectRow(i, true);
20456 for(var i = startRow; i >= endRow; i--){
20457 this.selectRow(i, true);
20463 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20464 * @param {Number} startRow The index of the first row in the range
20465 * @param {Number} endRow The index of the last row in the range
20467 deselectRange : function(startRow, endRow, preventViewNotify){
20468 if(this.locked) return;
20469 for(var i = startRow; i <= endRow; i++){
20470 this.deselectRow(i, preventViewNotify);
20476 * @param {Number} row The index of the row to select
20477 * @param {Boolean} keepExisting (optional) True to keep existing selections
20479 selectRow : function(index, keepExisting, preventViewNotify){
20480 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20481 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20482 if(!keepExisting || this.singleSelect){
20483 this.clearSelections();
20485 var r = this.grid.dataSource.getAt(index);
20486 this.selections.add(r);
20487 this.last = this.lastActive = index;
20488 if(!preventViewNotify){
20489 this.grid.getView().onRowSelect(index);
20491 this.fireEvent("rowselect", this, index, r);
20492 this.fireEvent("selectionchange", this);
20498 * @param {Number} row The index of the row to deselect
20500 deselectRow : function(index, preventViewNotify){
20501 if(this.locked) return;
20502 if(this.last == index){
20505 if(this.lastActive == index){
20506 this.lastActive = false;
20508 var r = this.grid.dataSource.getAt(index);
20509 this.selections.remove(r);
20510 if(!preventViewNotify){
20511 this.grid.getView().onRowDeselect(index);
20513 this.fireEvent("rowdeselect", this, index);
20514 this.fireEvent("selectionchange", this);
20518 restoreLast : function(){
20520 this.last = this._last;
20525 acceptsNav : function(row, col, cm){
20526 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20530 onEditorKey : function(field, e){
20531 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20536 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20538 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20540 }else if(k == e.ENTER && !e.ctrlKey){
20544 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20546 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20548 }else if(k == e.ESC){
20552 g.startEditing(newCell[0], newCell[1]);
20557 * Ext JS Library 1.1.1
20558 * Copyright(c) 2006-2007, Ext JS, LLC.
20560 * Originally Released Under LGPL - original licence link has changed is not relivant.
20563 * <script type="text/javascript">
20567 * @class Roo.bootstrap.PagingToolbar
20569 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20571 * Create a new PagingToolbar
20572 * @param {Object} config The config object
20574 Roo.bootstrap.PagingToolbar = function(config)
20576 // old args format still supported... - xtype is prefered..
20577 // created from xtype...
20578 var ds = config.dataSource;
20579 this.toolbarItems = [];
20580 if (config.items) {
20581 this.toolbarItems = config.items;
20582 // config.items = [];
20585 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20592 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20596 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20598 * @cfg {Roo.data.Store} dataSource
20599 * The underlying data store providing the paged data
20602 * @cfg {String/HTMLElement/Element} container
20603 * container The id or element that will contain the toolbar
20606 * @cfg {Boolean} displayInfo
20607 * True to display the displayMsg (defaults to false)
20610 * @cfg {Number} pageSize
20611 * The number of records to display per page (defaults to 20)
20615 * @cfg {String} displayMsg
20616 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20618 displayMsg : 'Displaying {0} - {1} of {2}',
20620 * @cfg {String} emptyMsg
20621 * The message to display when no records are found (defaults to "No data to display")
20623 emptyMsg : 'No data to display',
20625 * Customizable piece of the default paging text (defaults to "Page")
20628 beforePageText : "Page",
20630 * Customizable piece of the default paging text (defaults to "of %0")
20633 afterPageText : "of {0}",
20635 * Customizable piece of the default paging text (defaults to "First Page")
20638 firstText : "First Page",
20640 * Customizable piece of the default paging text (defaults to "Previous Page")
20643 prevText : "Previous Page",
20645 * Customizable piece of the default paging text (defaults to "Next Page")
20648 nextText : "Next Page",
20650 * Customizable piece of the default paging text (defaults to "Last Page")
20653 lastText : "Last Page",
20655 * Customizable piece of the default paging text (defaults to "Refresh")
20658 refreshText : "Refresh",
20662 onRender : function(ct, position)
20664 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20665 this.navgroup.parentId = this.id;
20666 this.navgroup.onRender(this.el, null);
20667 // add the buttons to the navgroup
20669 if(this.displayInfo){
20670 Roo.log(this.el.select('ul.navbar-nav',true).first());
20671 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20672 this.displayEl = this.el.select('.x-paging-info', true).first();
20673 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20674 // this.displayEl = navel.el.select('span',true).first();
20680 Roo.each(_this.buttons, function(e){
20681 Roo.factory(e).onRender(_this.el, null);
20685 Roo.each(_this.toolbarItems, function(e) {
20686 _this.navgroup.addItem(e);
20690 this.first = this.navgroup.addItem({
20691 tooltip: this.firstText,
20693 icon : 'fa fa-backward',
20695 preventDefault: true,
20696 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20699 this.prev = this.navgroup.addItem({
20700 tooltip: this.prevText,
20702 icon : 'fa fa-step-backward',
20704 preventDefault: true,
20705 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20707 //this.addSeparator();
20710 var field = this.navgroup.addItem( {
20712 cls : 'x-paging-position',
20714 html : this.beforePageText +
20715 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20716 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20719 this.field = field.el.select('input', true).first();
20720 this.field.on("keydown", this.onPagingKeydown, this);
20721 this.field.on("focus", function(){this.dom.select();});
20724 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20725 //this.field.setHeight(18);
20726 //this.addSeparator();
20727 this.next = this.navgroup.addItem({
20728 tooltip: this.nextText,
20730 html : ' <i class="fa fa-step-forward">',
20732 preventDefault: true,
20733 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20735 this.last = this.navgroup.addItem({
20736 tooltip: this.lastText,
20737 icon : 'fa fa-forward',
20740 preventDefault: true,
20741 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20743 //this.addSeparator();
20744 this.loading = this.navgroup.addItem({
20745 tooltip: this.refreshText,
20746 icon: 'fa fa-refresh',
20747 preventDefault: true,
20748 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20754 updateInfo : function(){
20755 if(this.displayEl){
20756 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20757 var msg = count == 0 ?
20761 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20763 this.displayEl.update(msg);
20768 onLoad : function(ds, r, o){
20769 this.cursor = o.params ? o.params.start : 0;
20770 var d = this.getPageData(),
20774 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20775 this.field.dom.value = ap;
20776 this.first.setDisabled(ap == 1);
20777 this.prev.setDisabled(ap == 1);
20778 this.next.setDisabled(ap == ps);
20779 this.last.setDisabled(ap == ps);
20780 this.loading.enable();
20785 getPageData : function(){
20786 var total = this.ds.getTotalCount();
20789 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20790 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20795 onLoadError : function(){
20796 this.loading.enable();
20800 onPagingKeydown : function(e){
20801 var k = e.getKey();
20802 var d = this.getPageData();
20804 var v = this.field.dom.value, pageNum;
20805 if(!v || isNaN(pageNum = parseInt(v, 10))){
20806 this.field.dom.value = d.activePage;
20809 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20810 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20813 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))
20815 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20816 this.field.dom.value = pageNum;
20817 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20820 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20822 var v = this.field.dom.value, pageNum;
20823 var increment = (e.shiftKey) ? 10 : 1;
20824 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20826 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20827 this.field.dom.value = d.activePage;
20830 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20832 this.field.dom.value = parseInt(v, 10) + increment;
20833 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20834 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20841 beforeLoad : function(){
20843 this.loading.disable();
20848 onClick : function(which){
20857 ds.load({params:{start: 0, limit: this.pageSize}});
20860 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20863 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20866 var total = ds.getTotalCount();
20867 var extra = total % this.pageSize;
20868 var lastStart = extra ? (total - extra) : total-this.pageSize;
20869 ds.load({params:{start: lastStart, limit: this.pageSize}});
20872 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20878 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20879 * @param {Roo.data.Store} store The data store to unbind
20881 unbind : function(ds){
20882 ds.un("beforeload", this.beforeLoad, this);
20883 ds.un("load", this.onLoad, this);
20884 ds.un("loadexception", this.onLoadError, this);
20885 ds.un("remove", this.updateInfo, this);
20886 ds.un("add", this.updateInfo, this);
20887 this.ds = undefined;
20891 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20892 * @param {Roo.data.Store} store The data store to bind
20894 bind : function(ds){
20895 ds.on("beforeload", this.beforeLoad, this);
20896 ds.on("load", this.onLoad, this);
20897 ds.on("loadexception", this.onLoadError, this);
20898 ds.on("remove", this.updateInfo, this);
20899 ds.on("add", this.updateInfo, this);
20910 * @class Roo.bootstrap.MessageBar
20911 * @extends Roo.bootstrap.Component
20912 * Bootstrap MessageBar class
20913 * @cfg {String} html contents of the MessageBar
20914 * @cfg {String} weight (info | success | warning | danger) default info
20915 * @cfg {String} beforeClass insert the bar before the given class
20916 * @cfg {Boolean} closable (true | false) default false
20917 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20920 * Create a new Element
20921 * @param {Object} config The config object
20924 Roo.bootstrap.MessageBar = function(config){
20925 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20928 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20934 beforeClass: 'bootstrap-sticky-wrap',
20936 getAutoCreate : function(){
20940 cls: 'alert alert-dismissable alert-' + this.weight,
20945 html: this.html || ''
20951 cfg.cls += ' alert-messages-fixed';
20965 onRender : function(ct, position)
20967 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20970 var cfg = Roo.apply({}, this.getAutoCreate());
20974 cfg.cls += ' ' + this.cls;
20977 cfg.style = this.style;
20979 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20981 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20984 this.el.select('>button.close').on('click', this.hide, this);
20990 if (!this.rendered) {
20996 this.fireEvent('show', this);
21002 if (!this.rendered) {
21008 this.fireEvent('hide', this);
21011 update : function()
21013 // var e = this.el.dom.firstChild;
21015 // if(this.closable){
21016 // e = e.nextSibling;
21019 // e.data = this.html || '';
21021 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21037 * @class Roo.bootstrap.Graph
21038 * @extends Roo.bootstrap.Component
21039 * Bootstrap Graph class
21043 @cfg {String} graphtype bar | vbar | pie
21044 @cfg {number} g_x coodinator | centre x (pie)
21045 @cfg {number} g_y coodinator | centre y (pie)
21046 @cfg {number} g_r radius (pie)
21047 @cfg {number} g_height height of the chart (respected by all elements in the set)
21048 @cfg {number} g_width width of the chart (respected by all elements in the set)
21049 @cfg {Object} title The title of the chart
21052 -opts (object) options for the chart
21054 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21055 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21057 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.
21058 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21060 o stretch (boolean)
21062 -opts (object) options for the pie
21065 o startAngle (number)
21066 o endAngle (number)
21070 * Create a new Input
21071 * @param {Object} config The config object
21074 Roo.bootstrap.Graph = function(config){
21075 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21081 * The img click event for the img.
21082 * @param {Roo.EventObject} e
21088 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21099 //g_colors: this.colors,
21106 getAutoCreate : function(){
21117 onRender : function(ct,position){
21118 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21119 this.raphael = Raphael(this.el.dom);
21121 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21122 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21123 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21124 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21126 r.text(160, 10, "Single Series Chart").attr(txtattr);
21127 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21128 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21129 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21131 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21132 r.barchart(330, 10, 300, 220, data1);
21133 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21134 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21137 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21138 // r.barchart(30, 30, 560, 250, xdata, {
21139 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21140 // axis : "0 0 1 1",
21141 // axisxlabels : xdata
21142 // //yvalues : cols,
21145 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21147 // this.load(null,xdata,{
21148 // axis : "0 0 1 1",
21149 // axisxlabels : xdata
21154 load : function(graphtype,xdata,opts){
21155 this.raphael.clear();
21157 graphtype = this.graphtype;
21162 var r = this.raphael,
21163 fin = function () {
21164 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21166 fout = function () {
21167 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21169 pfin = function() {
21170 this.sector.stop();
21171 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21174 this.label[0].stop();
21175 this.label[0].attr({ r: 7.5 });
21176 this.label[1].attr({ "font-weight": 800 });
21179 pfout = function() {
21180 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21183 this.label[0].animate({ r: 5 }, 500, "bounce");
21184 this.label[1].attr({ "font-weight": 400 });
21190 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21193 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21196 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21197 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21199 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21206 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21211 setTitle: function(o)
21216 initEvents: function() {
21219 this.el.on('click', this.onClick, this);
21223 onClick : function(e)
21225 Roo.log('img onclick');
21226 this.fireEvent('click', this, e);
21238 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21241 * @class Roo.bootstrap.dash.NumberBox
21242 * @extends Roo.bootstrap.Component
21243 * Bootstrap NumberBox class
21244 * @cfg {String} headline Box headline
21245 * @cfg {String} content Box content
21246 * @cfg {String} icon Box icon
21247 * @cfg {String} footer Footer text
21248 * @cfg {String} fhref Footer href
21251 * Create a new NumberBox
21252 * @param {Object} config The config object
21256 Roo.bootstrap.dash.NumberBox = function(config){
21257 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21261 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21270 getAutoCreate : function(){
21274 cls : 'small-box ',
21282 cls : 'roo-headline',
21283 html : this.headline
21287 cls : 'roo-content',
21288 html : this.content
21302 cls : 'ion ' + this.icon
21311 cls : 'small-box-footer',
21312 href : this.fhref || '#',
21316 cfg.cn.push(footer);
21323 onRender : function(ct,position){
21324 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21331 setHeadline: function (value)
21333 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21336 setFooter: function (value, href)
21338 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21341 this.el.select('a.small-box-footer',true).first().attr('href', href);
21346 setContent: function (value)
21348 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21351 initEvents: function()
21365 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21368 * @class Roo.bootstrap.dash.TabBox
21369 * @extends Roo.bootstrap.Component
21370 * Bootstrap TabBox class
21371 * @cfg {String} title Title of the TabBox
21372 * @cfg {String} icon Icon of the TabBox
21373 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21374 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21377 * Create a new TabBox
21378 * @param {Object} config The config object
21382 Roo.bootstrap.dash.TabBox = function(config){
21383 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21388 * When a pane is added
21389 * @param {Roo.bootstrap.dash.TabPane} pane
21393 * @event activatepane
21394 * When a pane is activated
21395 * @param {Roo.bootstrap.dash.TabPane} pane
21397 "activatepane" : true
21405 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21410 tabScrollable : false,
21412 getChildContainer : function()
21414 return this.el.select('.tab-content', true).first();
21417 getAutoCreate : function(){
21421 cls: 'pull-left header',
21429 cls: 'fa ' + this.icon
21435 cls: 'nav nav-tabs pull-right',
21441 if(this.tabScrollable){
21448 cls: 'nav nav-tabs pull-right',
21459 cls: 'nav-tabs-custom',
21464 cls: 'tab-content no-padding',
21472 initEvents : function()
21474 //Roo.log('add add pane handler');
21475 this.on('addpane', this.onAddPane, this);
21478 * Updates the box title
21479 * @param {String} html to set the title to.
21481 setTitle : function(value)
21483 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21485 onAddPane : function(pane)
21487 this.panes.push(pane);
21488 //Roo.log('addpane');
21490 // tabs are rendere left to right..
21491 if(!this.showtabs){
21495 var ctr = this.el.select('.nav-tabs', true).first();
21498 var existing = ctr.select('.nav-tab',true);
21499 var qty = existing.getCount();;
21502 var tab = ctr.createChild({
21504 cls : 'nav-tab' + (qty ? '' : ' active'),
21512 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21515 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21517 pane.el.addClass('active');
21522 onTabClick : function(ev,un,ob,pane)
21524 //Roo.log('tab - prev default');
21525 ev.preventDefault();
21528 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21529 pane.tab.addClass('active');
21530 //Roo.log(pane.title);
21531 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21532 // technically we should have a deactivate event.. but maybe add later.
21533 // and it should not de-activate the selected tab...
21534 this.fireEvent('activatepane', pane);
21535 pane.el.addClass('active');
21536 pane.fireEvent('activate');
21541 getActivePane : function()
21544 Roo.each(this.panes, function(p) {
21545 if(p.el.hasClass('active')){
21566 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21568 * @class Roo.bootstrap.TabPane
21569 * @extends Roo.bootstrap.Component
21570 * Bootstrap TabPane class
21571 * @cfg {Boolean} active (false | true) Default false
21572 * @cfg {String} title title of panel
21576 * Create a new TabPane
21577 * @param {Object} config The config object
21580 Roo.bootstrap.dash.TabPane = function(config){
21581 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21587 * When a pane is activated
21588 * @param {Roo.bootstrap.dash.TabPane} pane
21595 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21600 // the tabBox that this is attached to.
21603 getAutoCreate : function()
21611 cfg.cls += ' active';
21616 initEvents : function()
21618 //Roo.log('trigger add pane handler');
21619 this.parent().fireEvent('addpane', this)
21623 * Updates the tab title
21624 * @param {String} html to set the title to.
21626 setTitle: function(str)
21632 this.tab.select('a', true).first().dom.innerHTML = str;
21649 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21652 * @class Roo.bootstrap.menu.Menu
21653 * @extends Roo.bootstrap.Component
21654 * Bootstrap Menu class - container for Menu
21655 * @cfg {String} html Text of the menu
21656 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21657 * @cfg {String} icon Font awesome icon
21658 * @cfg {String} pos Menu align to (top | bottom) default bottom
21662 * Create a new Menu
21663 * @param {Object} config The config object
21667 Roo.bootstrap.menu.Menu = function(config){
21668 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21672 * @event beforeshow
21673 * Fires before this menu is displayed
21674 * @param {Roo.bootstrap.menu.Menu} this
21678 * @event beforehide
21679 * Fires before this menu is hidden
21680 * @param {Roo.bootstrap.menu.Menu} this
21685 * Fires after this menu is displayed
21686 * @param {Roo.bootstrap.menu.Menu} this
21691 * Fires after this menu is hidden
21692 * @param {Roo.bootstrap.menu.Menu} this
21697 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21698 * @param {Roo.bootstrap.menu.Menu} this
21699 * @param {Roo.EventObject} e
21706 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21710 weight : 'default',
21715 getChildContainer : function() {
21716 if(this.isSubMenu){
21720 return this.el.select('ul.dropdown-menu', true).first();
21723 getAutoCreate : function()
21728 cls : 'roo-menu-text',
21736 cls : 'fa ' + this.icon
21747 cls : 'dropdown-button btn btn-' + this.weight,
21752 cls : 'dropdown-toggle btn btn-' + this.weight,
21762 cls : 'dropdown-menu'
21768 if(this.pos == 'top'){
21769 cfg.cls += ' dropup';
21772 if(this.isSubMenu){
21775 cls : 'dropdown-menu'
21782 onRender : function(ct, position)
21784 this.isSubMenu = ct.hasClass('dropdown-submenu');
21786 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21789 initEvents : function()
21791 if(this.isSubMenu){
21795 this.hidden = true;
21797 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21798 this.triggerEl.on('click', this.onTriggerPress, this);
21800 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21801 this.buttonEl.on('click', this.onClick, this);
21807 if(this.isSubMenu){
21811 return this.el.select('ul.dropdown-menu', true).first();
21814 onClick : function(e)
21816 this.fireEvent("click", this, e);
21819 onTriggerPress : function(e)
21821 if (this.isVisible()) {
21828 isVisible : function(){
21829 return !this.hidden;
21834 this.fireEvent("beforeshow", this);
21836 this.hidden = false;
21837 this.el.addClass('open');
21839 Roo.get(document).on("mouseup", this.onMouseUp, this);
21841 this.fireEvent("show", this);
21848 this.fireEvent("beforehide", this);
21850 this.hidden = true;
21851 this.el.removeClass('open');
21853 Roo.get(document).un("mouseup", this.onMouseUp);
21855 this.fireEvent("hide", this);
21858 onMouseUp : function()
21872 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21875 * @class Roo.bootstrap.menu.Item
21876 * @extends Roo.bootstrap.Component
21877 * Bootstrap MenuItem class
21878 * @cfg {Boolean} submenu (true | false) default false
21879 * @cfg {String} html text of the item
21880 * @cfg {String} href the link
21881 * @cfg {Boolean} disable (true | false) default false
21882 * @cfg {Boolean} preventDefault (true | false) default true
21883 * @cfg {String} icon Font awesome icon
21884 * @cfg {String} pos Submenu align to (left | right) default right
21888 * Create a new Item
21889 * @param {Object} config The config object
21893 Roo.bootstrap.menu.Item = function(config){
21894 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21898 * Fires when the mouse is hovering over this menu
21899 * @param {Roo.bootstrap.menu.Item} this
21900 * @param {Roo.EventObject} e
21905 * Fires when the mouse exits this menu
21906 * @param {Roo.bootstrap.menu.Item} this
21907 * @param {Roo.EventObject} e
21913 * The raw click event for the entire grid.
21914 * @param {Roo.EventObject} e
21920 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21925 preventDefault: true,
21930 getAutoCreate : function()
21935 cls : 'roo-menu-item-text',
21943 cls : 'fa ' + this.icon
21952 href : this.href || '#',
21959 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21963 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21965 if(this.pos == 'left'){
21966 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21973 initEvents : function()
21975 this.el.on('mouseover', this.onMouseOver, this);
21976 this.el.on('mouseout', this.onMouseOut, this);
21978 this.el.select('a', true).first().on('click', this.onClick, this);
21982 onClick : function(e)
21984 if(this.preventDefault){
21985 e.preventDefault();
21988 this.fireEvent("click", this, e);
21991 onMouseOver : function(e)
21993 if(this.submenu && this.pos == 'left'){
21994 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21997 this.fireEvent("mouseover", this, e);
22000 onMouseOut : function(e)
22002 this.fireEvent("mouseout", this, e);
22014 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22017 * @class Roo.bootstrap.menu.Separator
22018 * @extends Roo.bootstrap.Component
22019 * Bootstrap Separator class
22022 * Create a new Separator
22023 * @param {Object} config The config object
22027 Roo.bootstrap.menu.Separator = function(config){
22028 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22031 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22033 getAutoCreate : function(){
22054 * @class Roo.bootstrap.Tooltip
22055 * Bootstrap Tooltip class
22056 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22057 * to determine which dom element triggers the tooltip.
22059 * It needs to add support for additional attributes like tooltip-position
22062 * Create a new Toolti
22063 * @param {Object} config The config object
22066 Roo.bootstrap.Tooltip = function(config){
22067 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22070 Roo.apply(Roo.bootstrap.Tooltip, {
22072 * @function init initialize tooltip monitoring.
22076 currentTip : false,
22077 currentRegion : false,
22083 Roo.get(document).on('mouseover', this.enter ,this);
22084 Roo.get(document).on('mouseout', this.leave, this);
22087 this.currentTip = new Roo.bootstrap.Tooltip();
22090 enter : function(ev)
22092 var dom = ev.getTarget();
22094 //Roo.log(['enter',dom]);
22095 var el = Roo.fly(dom);
22096 if (this.currentEl) {
22098 //Roo.log(this.currentEl);
22099 //Roo.log(this.currentEl.contains(dom));
22100 if (this.currentEl == el) {
22103 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22111 if (this.currentTip.el) {
22112 this.currentTip.el.hide(); // force hiding...
22117 // you can not look for children, as if el is the body.. then everythign is the child..
22118 if (!el.attr('tooltip')) { //
22119 if (!el.select("[tooltip]").elements.length) {
22122 // is the mouse over this child...?
22123 bindEl = el.select("[tooltip]").first();
22124 var xy = ev.getXY();
22125 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22126 //Roo.log("not in region.");
22129 //Roo.log("child element over..");
22132 this.currentEl = bindEl;
22133 this.currentTip.bind(bindEl);
22134 this.currentRegion = Roo.lib.Region.getRegion(dom);
22135 this.currentTip.enter();
22138 leave : function(ev)
22140 var dom = ev.getTarget();
22141 //Roo.log(['leave',dom]);
22142 if (!this.currentEl) {
22147 if (dom != this.currentEl.dom) {
22150 var xy = ev.getXY();
22151 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22154 // only activate leave if mouse cursor is outside... bounding box..
22159 if (this.currentTip) {
22160 this.currentTip.leave();
22162 //Roo.log('clear currentEl');
22163 this.currentEl = false;
22168 'left' : ['r-l', [-2,0], 'right'],
22169 'right' : ['l-r', [2,0], 'left'],
22170 'bottom' : ['t-b', [0,2], 'top'],
22171 'top' : [ 'b-t', [0,-2], 'bottom']
22177 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22182 delay : null, // can be { show : 300 , hide: 500}
22186 hoverState : null, //???
22188 placement : 'bottom',
22190 getAutoCreate : function(){
22197 cls : 'tooltip-arrow'
22200 cls : 'tooltip-inner'
22207 bind : function(el)
22213 enter : function () {
22215 if (this.timeout != null) {
22216 clearTimeout(this.timeout);
22219 this.hoverState = 'in';
22220 //Roo.log("enter - show");
22221 if (!this.delay || !this.delay.show) {
22226 this.timeout = setTimeout(function () {
22227 if (_t.hoverState == 'in') {
22230 }, this.delay.show);
22234 clearTimeout(this.timeout);
22236 this.hoverState = 'out';
22237 if (!this.delay || !this.delay.hide) {
22243 this.timeout = setTimeout(function () {
22244 //Roo.log("leave - timeout");
22246 if (_t.hoverState == 'out') {
22248 Roo.bootstrap.Tooltip.currentEl = false;
22256 this.render(document.body);
22259 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22261 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22263 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22265 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22267 var placement = typeof this.placement == 'function' ?
22268 this.placement.call(this, this.el, on_el) :
22271 var autoToken = /\s?auto?\s?/i;
22272 var autoPlace = autoToken.test(placement);
22274 placement = placement.replace(autoToken, '') || 'top';
22278 //this.el.setXY([0,0]);
22280 //this.el.dom.style.display='block';
22281 this.el.addClass(placement);
22283 //this.el.appendTo(on_el);
22285 var p = this.getPosition();
22286 var box = this.el.getBox();
22291 var align = Roo.bootstrap.Tooltip.alignment[placement];
22292 this.el.alignTo(this.bindEl, align[0],align[1]);
22293 //var arrow = this.el.select('.arrow',true).first();
22294 //arrow.set(align[2],
22296 this.el.addClass('in fade');
22297 this.hoverState = null;
22299 if (this.el.hasClass('fade')) {
22310 //this.el.setXY([0,0]);
22311 this.el.removeClass('in');
22327 * @class Roo.bootstrap.LocationPicker
22328 * @extends Roo.bootstrap.Component
22329 * Bootstrap LocationPicker class
22330 * @cfg {Number} latitude Position when init default 0
22331 * @cfg {Number} longitude Position when init default 0
22332 * @cfg {Number} zoom default 15
22333 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22334 * @cfg {Boolean} mapTypeControl default false
22335 * @cfg {Boolean} disableDoubleClickZoom default false
22336 * @cfg {Boolean} scrollwheel default true
22337 * @cfg {Boolean} streetViewControl default false
22338 * @cfg {Number} radius default 0
22339 * @cfg {String} locationName
22340 * @cfg {Boolean} draggable default true
22341 * @cfg {Boolean} enableAutocomplete default false
22342 * @cfg {Boolean} enableReverseGeocode default true
22343 * @cfg {String} markerTitle
22346 * Create a new LocationPicker
22347 * @param {Object} config The config object
22351 Roo.bootstrap.LocationPicker = function(config){
22353 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22358 * Fires when the picker initialized.
22359 * @param {Roo.bootstrap.LocationPicker} this
22360 * @param {Google Location} location
22364 * @event positionchanged
22365 * Fires when the picker position changed.
22366 * @param {Roo.bootstrap.LocationPicker} this
22367 * @param {Google Location} location
22369 positionchanged : true,
22372 * Fires when the map resize.
22373 * @param {Roo.bootstrap.LocationPicker} this
22378 * Fires when the map show.
22379 * @param {Roo.bootstrap.LocationPicker} this
22384 * Fires when the map hide.
22385 * @param {Roo.bootstrap.LocationPicker} this
22390 * Fires when click the map.
22391 * @param {Roo.bootstrap.LocationPicker} this
22392 * @param {Map event} e
22396 * @event mapRightClick
22397 * Fires when right click the map.
22398 * @param {Roo.bootstrap.LocationPicker} this
22399 * @param {Map event} e
22401 mapRightClick : true,
22403 * @event markerClick
22404 * Fires when click the marker.
22405 * @param {Roo.bootstrap.LocationPicker} this
22406 * @param {Map event} e
22408 markerClick : true,
22410 * @event markerRightClick
22411 * Fires when right click the marker.
22412 * @param {Roo.bootstrap.LocationPicker} this
22413 * @param {Map event} e
22415 markerRightClick : true,
22417 * @event OverlayViewDraw
22418 * Fires when OverlayView Draw
22419 * @param {Roo.bootstrap.LocationPicker} this
22421 OverlayViewDraw : true,
22423 * @event OverlayViewOnAdd
22424 * Fires when OverlayView Draw
22425 * @param {Roo.bootstrap.LocationPicker} this
22427 OverlayViewOnAdd : true,
22429 * @event OverlayViewOnRemove
22430 * Fires when OverlayView Draw
22431 * @param {Roo.bootstrap.LocationPicker} this
22433 OverlayViewOnRemove : true,
22435 * @event OverlayViewShow
22436 * Fires when OverlayView Draw
22437 * @param {Roo.bootstrap.LocationPicker} this
22438 * @param {Pixel} cpx
22440 OverlayViewShow : true,
22442 * @event OverlayViewHide
22443 * Fires when OverlayView Draw
22444 * @param {Roo.bootstrap.LocationPicker} this
22446 OverlayViewHide : true
22451 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22453 gMapContext: false,
22459 mapTypeControl: false,
22460 disableDoubleClickZoom: false,
22462 streetViewControl: false,
22466 enableAutocomplete: false,
22467 enableReverseGeocode: true,
22470 getAutoCreate: function()
22475 cls: 'roo-location-picker'
22481 initEvents: function(ct, position)
22483 if(!this.el.getWidth() || this.isApplied()){
22487 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22492 initial: function()
22494 if(!this.mapTypeId){
22495 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22498 this.gMapContext = this.GMapContext();
22500 this.initOverlayView();
22502 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22506 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22507 _this.setPosition(_this.gMapContext.marker.position);
22510 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22511 _this.fireEvent('mapClick', this, event);
22515 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22516 _this.fireEvent('mapRightClick', this, event);
22520 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22521 _this.fireEvent('markerClick', this, event);
22525 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22526 _this.fireEvent('markerRightClick', this, event);
22530 this.setPosition(this.gMapContext.location);
22532 this.fireEvent('initial', this, this.gMapContext.location);
22535 initOverlayView: function()
22539 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22543 _this.fireEvent('OverlayViewDraw', _this);
22548 _this.fireEvent('OverlayViewOnAdd', _this);
22551 onRemove: function()
22553 _this.fireEvent('OverlayViewOnRemove', _this);
22556 show: function(cpx)
22558 _this.fireEvent('OverlayViewShow', _this, cpx);
22563 _this.fireEvent('OverlayViewHide', _this);
22569 fromLatLngToContainerPixel: function(event)
22571 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22574 isApplied: function()
22576 return this.getGmapContext() == false ? false : true;
22579 getGmapContext: function()
22581 return this.gMapContext
22584 GMapContext: function()
22586 var position = new google.maps.LatLng(this.latitude, this.longitude);
22588 var _map = new google.maps.Map(this.el.dom, {
22591 mapTypeId: this.mapTypeId,
22592 mapTypeControl: this.mapTypeControl,
22593 disableDoubleClickZoom: this.disableDoubleClickZoom,
22594 scrollwheel: this.scrollwheel,
22595 streetViewControl: this.streetViewControl,
22596 locationName: this.locationName,
22597 draggable: this.draggable,
22598 enableAutocomplete: this.enableAutocomplete,
22599 enableReverseGeocode: this.enableReverseGeocode
22602 var _marker = new google.maps.Marker({
22603 position: position,
22605 title: this.markerTitle,
22606 draggable: this.draggable
22613 location: position,
22614 radius: this.radius,
22615 locationName: this.locationName,
22616 addressComponents: {
22617 formatted_address: null,
22618 addressLine1: null,
22619 addressLine2: null,
22621 streetNumber: null,
22625 stateOrProvince: null
22628 domContainer: this.el.dom,
22629 geodecoder: new google.maps.Geocoder()
22633 drawCircle: function(center, radius, options)
22635 if (this.gMapContext.circle != null) {
22636 this.gMapContext.circle.setMap(null);
22640 options = Roo.apply({}, options, {
22641 strokeColor: "#0000FF",
22642 strokeOpacity: .35,
22644 fillColor: "#0000FF",
22648 options.map = this.gMapContext.map;
22649 options.radius = radius;
22650 options.center = center;
22651 this.gMapContext.circle = new google.maps.Circle(options);
22652 return this.gMapContext.circle;
22658 setPosition: function(location)
22660 this.gMapContext.location = location;
22661 this.gMapContext.marker.setPosition(location);
22662 this.gMapContext.map.panTo(location);
22663 this.drawCircle(location, this.gMapContext.radius, {});
22667 if (this.gMapContext.settings.enableReverseGeocode) {
22668 this.gMapContext.geodecoder.geocode({
22669 latLng: this.gMapContext.location
22670 }, function(results, status) {
22672 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22673 _this.gMapContext.locationName = results[0].formatted_address;
22674 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22676 _this.fireEvent('positionchanged', this, location);
22683 this.fireEvent('positionchanged', this, location);
22688 google.maps.event.trigger(this.gMapContext.map, "resize");
22690 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22692 this.fireEvent('resize', this);
22695 setPositionByLatLng: function(latitude, longitude)
22697 this.setPosition(new google.maps.LatLng(latitude, longitude));
22700 getCurrentPosition: function()
22703 latitude: this.gMapContext.location.lat(),
22704 longitude: this.gMapContext.location.lng()
22708 getAddressName: function()
22710 return this.gMapContext.locationName;
22713 getAddressComponents: function()
22715 return this.gMapContext.addressComponents;
22718 address_component_from_google_geocode: function(address_components)
22722 for (var i = 0; i < address_components.length; i++) {
22723 var component = address_components[i];
22724 if (component.types.indexOf("postal_code") >= 0) {
22725 result.postalCode = component.short_name;
22726 } else if (component.types.indexOf("street_number") >= 0) {
22727 result.streetNumber = component.short_name;
22728 } else if (component.types.indexOf("route") >= 0) {
22729 result.streetName = component.short_name;
22730 } else if (component.types.indexOf("neighborhood") >= 0) {
22731 result.city = component.short_name;
22732 } else if (component.types.indexOf("locality") >= 0) {
22733 result.city = component.short_name;
22734 } else if (component.types.indexOf("sublocality") >= 0) {
22735 result.district = component.short_name;
22736 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22737 result.stateOrProvince = component.short_name;
22738 } else if (component.types.indexOf("country") >= 0) {
22739 result.country = component.short_name;
22743 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22744 result.addressLine2 = "";
22748 setZoomLevel: function(zoom)
22750 this.gMapContext.map.setZoom(zoom);
22763 this.fireEvent('show', this);
22774 this.fireEvent('hide', this);
22779 Roo.apply(Roo.bootstrap.LocationPicker, {
22781 OverlayView : function(map, options)
22783 options = options || {};
22797 * @class Roo.bootstrap.Alert
22798 * @extends Roo.bootstrap.Component
22799 * Bootstrap Alert class
22800 * @cfg {String} title The title of alert
22801 * @cfg {String} html The content of alert
22802 * @cfg {String} weight ( success | info | warning | danger )
22803 * @cfg {String} faicon font-awesomeicon
22806 * Create a new alert
22807 * @param {Object} config The config object
22811 Roo.bootstrap.Alert = function(config){
22812 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22816 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22823 getAutoCreate : function()
22832 cls : 'roo-alert-icon'
22837 cls : 'roo-alert-title',
22842 cls : 'roo-alert-text',
22849 cfg.cn[0].cls += ' fa ' + this.faicon;
22853 cfg.cls += ' alert-' + this.weight;
22859 initEvents: function()
22861 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22864 setTitle : function(str)
22866 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22869 setText : function(str)
22871 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22874 setWeight : function(weight)
22877 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22880 this.weight = weight;
22882 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22885 setIcon : function(icon)
22888 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22893 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);