4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
232 addxtypeChild : function (tree, cntr)
234 Roo.debug && Roo.log('addxtypeChild:' + cntr);
236 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
240 (typeof(tree['flexy:foreach']) != 'undefined');
244 skip_children = false;
245 // render the element if it's not BODY.
246 if (tree.xtype != 'Body') {
248 cn = Roo.factory(tree);
250 cn.parentType = this.xtype; //??
251 cn.parentId = this.id;
253 var build_from_html = Roo.XComponent.build_from_html;
256 // does the container contain child eleemnts with 'xtype' attributes.
257 // that match this xtype..
258 // note - when we render we create these as well..
259 // so we should check to see if body has xtype set.
260 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
262 var self_cntr_el = Roo.get(this[cntr](false));
263 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
265 Roo.log(Roo.XComponent.build_from_html);
266 Roo.log("got echild:");
269 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
270 // and are not displayed -this causes this to use up the wrong element when matching.
271 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
274 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
275 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
281 //echild.dom.removeAttribute('xtype');
283 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
284 Roo.debug && Roo.log(self_cntr_el);
285 Roo.debug && Roo.log(echild);
286 Roo.debug && Roo.log(cn);
292 // if object has flexy:if - then it may or may not be rendered.
293 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
294 // skip a flexy if element.
295 Roo.debug && Roo.log('skipping render');
296 Roo.debug && Roo.log(tree);
298 Roo.debug && Roo.log('skipping all children');
299 skip_children = true;
304 // actually if flexy:foreach is found, we really want to create
305 // multiple copies here...
307 //Roo.log(this[cntr]());
308 cn.render(this[cntr](true));
310 // then add the element..
318 if (typeof (tree.menu) != 'undefined') {
319 tree.menu.parentType = cn.xtype;
320 tree.menu.triggerEl = cn.el;
321 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
325 if (!tree.items || !tree.items.length) {
329 var items = tree.items;
332 //Roo.log(items.length);
334 if (!skip_children) {
335 for(var i =0;i < items.length;i++) {
336 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
342 this.fireEvent('childrenrendered', this);
358 * @class Roo.bootstrap.Body
359 * @extends Roo.bootstrap.Component
360 * Bootstrap Body class
364 * @param {Object} config The config object
367 Roo.bootstrap.Body = function(config){
368 Roo.bootstrap.Body.superclass.constructor.call(this, config);
369 this.el = Roo.get(document.body);
370 if (this.cls && this.cls.length) {
371 Roo.get(document.body).addClass(this.cls);
375 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
380 onRender : function(ct, position)
382 /* Roo.log("Roo.bootstrap.Body - onRender");
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
404 * @class Roo.bootstrap.ButtonGroup
405 * @extends Roo.bootstrap.Component
406 * Bootstrap ButtonGroup class
407 * @cfg {String} size lg | sm | xs (default empty normal)
408 * @cfg {String} align vertical | justified (default none)
409 * @cfg {String} direction up | down (default down)
410 * @cfg {Boolean} toolbar false | true
411 * @cfg {Boolean} btn true | false
416 * @param {Object} config The config object
419 Roo.bootstrap.ButtonGroup = function(config){
420 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
423 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
431 getAutoCreate : function(){
437 cfg.html = this.html || cfg.html;
448 if (['vertical','justified'].indexOf(this.align)!==-1) {
449 cfg.cls = 'btn-group-' + this.align;
451 if (this.align == 'justified') {
452 console.log(this.items);
456 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
457 cfg.cls += ' btn-group-' + this.size;
460 if (this.direction == 'up') {
461 cfg.cls += ' dropup' ;
477 * @class Roo.bootstrap.Button
478 * @extends Roo.bootstrap.Component
479 * Bootstrap Button class
480 * @cfg {String} html The button content
481 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
482 * @cfg {String} size ( lg | sm | xs)
483 * @cfg {String} tag ( a | input | submit)
484 * @cfg {String} href empty or href
485 * @cfg {Boolean} disabled default false;
486 * @cfg {Boolean} isClose default false;
487 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
488 * @cfg {String} badge text for badge
489 * @cfg {String} theme default
490 * @cfg {Boolean} inverse
491 * @cfg {Boolean} toggle
492 * @cfg {String} ontext text for on toggle state
493 * @cfg {String} offtext text for off toggle state
494 * @cfg {Boolean} defaulton
495 * @cfg {Boolean} preventDefault default true
496 * @cfg {Boolean} removeClass remove the standard class..
497 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
500 * Create a new button
501 * @param {Object} config The config object
505 Roo.bootstrap.Button = function(config){
506 Roo.bootstrap.Button.superclass.constructor.call(this, config);
511 * When a butotn is pressed
512 * @param {Roo.bootstrap.Button} this
513 * @param {Roo.EventObject} e
518 * After the button has been toggles
519 * @param {Roo.EventObject} e
520 * @param {boolean} pressed (also available as button.pressed)
526 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
544 preventDefault: true,
553 getAutoCreate : function(){
561 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
562 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
567 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
569 if (this.toggle == true) {
572 cls: 'slider-frame roo-button',
577 'data-off-text':'OFF',
578 cls: 'slider-button',
584 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585 cfg.cls += ' '+this.weight;
594 cfg["aria-hidden"] = true;
596 cfg.html = "×";
602 if (this.theme==='default') {
603 cfg.cls = 'btn roo-button';
605 //if (this.parentType != 'Navbar') {
606 this.weight = this.weight.length ? this.weight : 'default';
608 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
610 cfg.cls += ' btn-' + this.weight;
612 } else if (this.theme==='glow') {
615 cfg.cls = 'btn-glow roo-button';
617 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
619 cfg.cls += ' ' + this.weight;
625 this.cls += ' inverse';
630 cfg.cls += ' active';
634 cfg.disabled = 'disabled';
638 Roo.log('changing to ul' );
640 this.glyphicon = 'caret';
643 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
645 //gsRoo.log(this.parentType);
646 if (this.parentType === 'Navbar' && !this.parent().bar) {
647 Roo.log('changing to li?');
656 href : this.href || '#'
659 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
660 cfg.cls += ' dropdown';
667 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
669 if (this.glyphicon) {
670 cfg.html = ' ' + cfg.html;
675 cls: 'glyphicon glyphicon-' + this.glyphicon
685 // cfg.cls='btn roo-button';
689 var value = cfg.html;
694 cls: 'glyphicon glyphicon-' + this.glyphicon,
713 cfg.cls += ' dropdown';
714 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
717 if (cfg.tag !== 'a' && this.href !== '') {
718 throw "Tag must be a to set href.";
719 } else if (this.href.length > 0) {
720 cfg.href = this.href;
723 if(this.removeClass){
728 cfg.target = this.target;
733 initEvents: function() {
734 // Roo.log('init events?');
735 // Roo.log(this.el.dom);
738 if (typeof (this.menu) != 'undefined') {
739 this.menu.parentType = this.xtype;
740 this.menu.triggerEl = this.el;
741 this.addxtype(Roo.apply({}, this.menu));
745 if (this.el.hasClass('roo-button')) {
746 this.el.on('click', this.onClick, this);
748 this.el.select('.roo-button').on('click', this.onClick, this);
751 if(this.removeClass){
752 this.el.on('click', this.onClick, this);
755 this.el.enableDisplayMode();
758 onClick : function(e)
765 Roo.log('button on click ');
766 if(this.preventDefault){
769 if (this.pressed === true || this.pressed === false) {
770 this.pressed = !this.pressed;
771 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
772 this.fireEvent('toggle', this, e, this.pressed);
776 this.fireEvent('click', this, e);
780 * Enables this button
784 this.disabled = false;
785 this.el.removeClass('disabled');
789 * Disable this button
793 this.disabled = true;
794 this.el.addClass('disabled');
797 * sets the active state on/off,
798 * @param {Boolean} state (optional) Force a particular state
800 setActive : function(v) {
802 this.el[v ? 'addClass' : 'removeClass']('active');
805 * toggles the current active state
807 toggleActive : function()
809 var active = this.el.hasClass('active');
810 this.setActive(!active);
814 setText : function(str)
816 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
820 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
843 * @class Roo.bootstrap.Column
844 * @extends Roo.bootstrap.Component
845 * Bootstrap Column class
846 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
847 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
848 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
849 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
850 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
851 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
852 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
853 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
856 * @cfg {Boolean} hidden (true|false) hide the element
857 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
858 * @cfg {String} fa (ban|check|...) font awesome icon
859 * @cfg {Number} fasize (1|2|....) font awsome size
861 * @cfg {String} icon (info-sign|check|...) glyphicon name
863 * @cfg {String} html content of column.
866 * Create a new Column
867 * @param {Object} config The config object
870 Roo.bootstrap.Column = function(config){
871 Roo.bootstrap.Column.superclass.constructor.call(this, config);
874 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
892 getAutoCreate : function(){
893 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
901 ['xs','sm','md','lg'].map(function(size){
902 //Roo.log( size + ':' + settings[size]);
904 if (settings[size+'off'] !== false) {
905 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
908 if (settings[size] === false) {
911 Roo.log(settings[size]);
912 if (!settings[size]) { // 0 = hidden
913 cfg.cls += ' hidden-' + size;
916 cfg.cls += ' col-' + size + '-' + settings[size];
921 cfg.cls += ' hidden';
924 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
925 cfg.cls +=' alert alert-' + this.alert;
929 if (this.html.length) {
930 cfg.html = this.html;
934 if (this.fasize > 1) {
935 fasize = ' fa-' + this.fasize + 'x';
937 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
942 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
961 * @class Roo.bootstrap.Container
962 * @extends Roo.bootstrap.Component
963 * Bootstrap Container class
964 * @cfg {Boolean} jumbotron is it a jumbotron element
965 * @cfg {String} html content of element
966 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
967 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
968 * @cfg {String} header content of header (for panel)
969 * @cfg {String} footer content of footer (for panel)
970 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
971 * @cfg {String} tag (header|aside|section) type of HTML tag.
972 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
973 * @cfg {String} fa (ban|check|...) font awesome icon
974 * @cfg {String} icon (info-sign|check|...) glyphicon name
975 * @cfg {Boolean} hidden (true|false) hide the element
979 * Create a new Container
980 * @param {Object} config The config object
983 Roo.bootstrap.Container = function(config){
984 Roo.bootstrap.Container.superclass.constructor.call(this, config);
987 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1001 getChildContainer : function() {
1007 if (this.panel.length) {
1008 return this.el.select('.panel-body',true).first();
1015 getAutoCreate : function(){
1018 tag : this.tag || 'div',
1022 if (this.jumbotron) {
1023 cfg.cls = 'jumbotron';
1028 // - this is applied by the parent..
1030 // cfg.cls = this.cls + '';
1033 if (this.sticky.length) {
1035 var bd = Roo.get(document.body);
1036 if (!bd.hasClass('bootstrap-sticky')) {
1037 bd.addClass('bootstrap-sticky');
1038 Roo.select('html',true).setStyle('height', '100%');
1041 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1045 if (this.well.length) {
1046 switch (this.well) {
1049 cfg.cls +=' well well-' +this.well;
1058 cfg.cls += ' hidden';
1062 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1063 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.panel.length) {
1069 cfg.cls += ' panel panel-' + this.panel;
1071 if (this.header.length) {
1074 cls : 'panel-heading',
1077 cls : 'panel-title',
1090 if (this.footer.length) {
1092 cls : 'panel-footer',
1101 body.html = this.html || cfg.html;
1102 // prefix with the icons..
1104 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1107 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1112 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1113 cfg.cls = 'container';
1119 titleEl : function()
1121 if(!this.el || !this.panel.length || !this.header.length){
1125 return this.el.select('.panel-title',true).first();
1128 setTitle : function(v)
1130 var titleEl = this.titleEl();
1136 titleEl.dom.innerHTML = v;
1139 getTitle : function()
1142 var titleEl = this.titleEl();
1148 return titleEl.dom.innerHTML;
1152 this.el.removeClass('hidden');
1155 if (!this.el.hasClass('hidden')) {
1156 this.el.addClass('hidden');
1172 * @class Roo.bootstrap.Img
1173 * @extends Roo.bootstrap.Component
1174 * Bootstrap Img class
1175 * @cfg {Boolean} imgResponsive false | true
1176 * @cfg {String} border rounded | circle | thumbnail
1177 * @cfg {String} src image source
1178 * @cfg {String} alt image alternative text
1179 * @cfg {String} href a tag href
1180 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1183 * Create a new Input
1184 * @param {Object} config The config object
1187 Roo.bootstrap.Img = function(config){
1188 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1194 * The img click event for the img.
1195 * @param {Roo.EventObject} e
1201 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1203 imgResponsive: true,
1209 getAutoCreate : function(){
1213 cls: (this.imgResponsive) ? 'img-responsive' : '',
1217 cfg.html = this.html || cfg.html;
1219 cfg.src = this.src || cfg.src;
1221 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1222 cfg.cls += ' img-' + this.border;
1239 a.target = this.target;
1245 return (this.href) ? a : cfg;
1248 initEvents: function() {
1251 this.el.on('click', this.onClick, this);
1255 onClick : function(e)
1257 Roo.log('img onclick');
1258 this.fireEvent('click', this, e);
1272 * @class Roo.bootstrap.Link
1273 * @extends Roo.bootstrap.Component
1274 * Bootstrap Link Class
1275 * @cfg {String} alt image alternative text
1276 * @cfg {String} href a tag href
1277 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1278 * @cfg {String} html the content of the link.
1279 * @cfg {String} anchor name for the anchor link
1281 * @cfg {Boolean} preventDefault (true | false) default false
1285 * Create a new Input
1286 * @param {Object} config The config object
1289 Roo.bootstrap.Link = function(config){
1290 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1296 * The img click event for the img.
1297 * @param {Roo.EventObject} e
1303 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1307 preventDefault: false,
1311 getAutoCreate : function()
1317 // anchor's do not require html/href...
1318 if (this.anchor === false) {
1319 cfg.html = this.html || 'html-missing';
1320 cfg.href = this.href || '#';
1322 cfg.name = this.anchor;
1323 if (this.html !== false) {
1324 cfg.html = this.html;
1326 if (this.href !== false) {
1327 cfg.href = this.href;
1331 if(this.alt !== false){
1336 if(this.target !== false) {
1337 cfg.target = this.target;
1343 initEvents: function() {
1345 if(!this.href || this.preventDefault){
1346 this.el.on('click', this.onClick, this);
1350 onClick : function(e)
1352 if(this.preventDefault){
1355 //Roo.log('img onclick');
1356 this.fireEvent('click', this, e);
1369 * @class Roo.bootstrap.Header
1370 * @extends Roo.bootstrap.Component
1371 * Bootstrap Header class
1372 * @cfg {String} html content of header
1373 * @cfg {Number} level (1|2|3|4|5|6) default 1
1376 * Create a new Header
1377 * @param {Object} config The config object
1381 Roo.bootstrap.Header = function(config){
1382 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1385 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1393 getAutoCreate : function(){
1398 tag: 'h' + (1 *this.level),
1399 html: this.html || ''
1411 * Ext JS Library 1.1.1
1412 * Copyright(c) 2006-2007, Ext JS, LLC.
1414 * Originally Released Under LGPL - original licence link has changed is not relivant.
1417 * <script type="text/javascript">
1421 * @class Roo.bootstrap.MenuMgr
1422 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1425 Roo.bootstrap.MenuMgr = function(){
1426 var menus, active, groups = {}, attached = false, lastShow = new Date();
1428 // private - called when first menu is created
1431 active = new Roo.util.MixedCollection();
1432 Roo.get(document).addKeyListener(27, function(){
1433 if(active.length > 0){
1441 if(active && active.length > 0){
1442 var c = active.clone();
1452 if(active.length < 1){
1453 Roo.get(document).un("mouseup", onMouseDown);
1461 var last = active.last();
1462 lastShow = new Date();
1465 Roo.get(document).on("mouseup", onMouseDown);
1470 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1471 m.parentMenu.activeChild = m;
1472 }else if(last && last.isVisible()){
1473 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1478 function onBeforeHide(m){
1480 m.activeChild.hide();
1482 if(m.autoHideTimer){
1483 clearTimeout(m.autoHideTimer);
1484 delete m.autoHideTimer;
1489 function onBeforeShow(m){
1490 var pm = m.parentMenu;
1491 if(!pm && !m.allowOtherMenus){
1493 }else if(pm && pm.activeChild && active != m){
1494 pm.activeChild.hide();
1499 function onMouseDown(e){
1500 Roo.log("on MouseDown");
1501 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1509 function onBeforeCheck(mi, state){
1511 var g = groups[mi.group];
1512 for(var i = 0, l = g.length; i < l; i++){
1514 g[i].setChecked(false);
1523 * Hides all menus that are currently visible
1525 hideAll : function(){
1530 register : function(menu){
1534 menus[menu.id] = menu;
1535 menu.on("beforehide", onBeforeHide);
1536 menu.on("hide", onHide);
1537 menu.on("beforeshow", onBeforeShow);
1538 menu.on("show", onShow);
1540 if(g && menu.events["checkchange"]){
1544 groups[g].push(menu);
1545 menu.on("checkchange", onCheck);
1550 * Returns a {@link Roo.menu.Menu} object
1551 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1552 * be used to generate and return a new Menu instance.
1554 get : function(menu){
1555 if(typeof menu == "string"){ // menu id
1557 }else if(menu.events){ // menu instance
1560 /*else if(typeof menu.length == 'number'){ // array of menu items?
1561 return new Roo.bootstrap.Menu({items:menu});
1562 }else{ // otherwise, must be a config
1563 return new Roo.bootstrap.Menu(menu);
1570 unregister : function(menu){
1571 delete menus[menu.id];
1572 menu.un("beforehide", onBeforeHide);
1573 menu.un("hide", onHide);
1574 menu.un("beforeshow", onBeforeShow);
1575 menu.un("show", onShow);
1577 if(g && menu.events["checkchange"]){
1578 groups[g].remove(menu);
1579 menu.un("checkchange", onCheck);
1584 registerCheckable : function(menuItem){
1585 var g = menuItem.group;
1590 groups[g].push(menuItem);
1591 menuItem.on("beforecheckchange", onBeforeCheck);
1596 unregisterCheckable : function(menuItem){
1597 var g = menuItem.group;
1599 groups[g].remove(menuItem);
1600 menuItem.un("beforecheckchange", onBeforeCheck);
1612 * @class Roo.bootstrap.Menu
1613 * @extends Roo.bootstrap.Component
1614 * Bootstrap Menu class - container for MenuItems
1615 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1619 * @param {Object} config The config object
1623 Roo.bootstrap.Menu = function(config){
1624 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1625 if (this.registerMenu) {
1626 Roo.bootstrap.MenuMgr.register(this);
1631 * Fires before this menu is displayed
1632 * @param {Roo.menu.Menu} this
1637 * Fires before this menu is hidden
1638 * @param {Roo.menu.Menu} this
1643 * Fires after this menu is displayed
1644 * @param {Roo.menu.Menu} this
1649 * Fires after this menu is hidden
1650 * @param {Roo.menu.Menu} this
1655 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1656 * @param {Roo.menu.Menu} this
1657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658 * @param {Roo.EventObject} e
1663 * Fires when the mouse is hovering over this menu
1664 * @param {Roo.menu.Menu} this
1665 * @param {Roo.EventObject} e
1666 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1671 * Fires when the mouse exits this menu
1672 * @param {Roo.menu.Menu} this
1673 * @param {Roo.EventObject} e
1674 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1679 * Fires when a menu item contained in this menu is clicked
1680 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1681 * @param {Roo.EventObject} e
1685 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1688 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1692 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1695 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1697 registerMenu : true,
1699 menuItems :false, // stores the menu items..
1705 getChildContainer : function() {
1709 getAutoCreate : function(){
1711 //if (['right'].indexOf(this.align)!==-1) {
1712 // cfg.cn[1].cls += ' pull-right'
1718 cls : 'dropdown-menu' ,
1719 style : 'z-index:1000'
1723 if (this.type === 'submenu') {
1724 cfg.cls = 'submenu active';
1726 if (this.type === 'treeview') {
1727 cfg.cls = 'treeview-menu';
1732 initEvents : function() {
1734 // Roo.log("ADD event");
1735 // Roo.log(this.triggerEl.dom);
1736 this.triggerEl.on('click', this.onTriggerPress, this);
1737 this.triggerEl.addClass('dropdown-toggle');
1738 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1740 this.el.on("mouseover", this.onMouseOver, this);
1741 this.el.on("mouseout", this.onMouseOut, this);
1745 findTargetItem : function(e){
1746 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1750 //Roo.log(t); Roo.log(t.id);
1752 //Roo.log(this.menuitems);
1753 return this.menuitems.get(t.id);
1755 //return this.items.get(t.menuItemId);
1760 onClick : function(e){
1761 Roo.log("menu.onClick");
1762 var t = this.findTargetItem(e);
1763 if(!t || t.isContainer){
1768 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1769 if(t == this.activeItem && t.shouldDeactivate(e)){
1770 this.activeItem.deactivate();
1771 delete this.activeItem;
1775 this.setActiveItem(t, true);
1783 Roo.log('pass click event');
1787 this.fireEvent("click", this, t, e);
1791 onMouseOver : function(e){
1792 var t = this.findTargetItem(e);
1795 // if(t.canActivate && !t.disabled){
1796 // this.setActiveItem(t, true);
1800 this.fireEvent("mouseover", this, e, t);
1802 isVisible : function(){
1803 return !this.hidden;
1805 onMouseOut : function(e){
1806 var t = this.findTargetItem(e);
1809 // if(t == this.activeItem && t.shouldDeactivate(e)){
1810 // this.activeItem.deactivate();
1811 // delete this.activeItem;
1814 this.fireEvent("mouseout", this, e, t);
1819 * Displays this menu relative to another element
1820 * @param {String/HTMLElement/Roo.Element} element The element to align to
1821 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1822 * the element (defaults to this.defaultAlign)
1823 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1825 show : function(el, pos, parentMenu){
1826 this.parentMenu = parentMenu;
1830 this.fireEvent("beforeshow", this);
1831 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1834 * Displays this menu at a specific xy position
1835 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1836 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1838 showAt : function(xy, parentMenu, /* private: */_e){
1839 this.parentMenu = parentMenu;
1844 this.fireEvent("beforeshow", this);
1846 //xy = this.el.adjustForConstraints(xy);
1848 //this.el.setXY(xy);
1850 this.hideMenuItems();
1851 this.hidden = false;
1852 this.triggerEl.addClass('open');
1854 this.fireEvent("show", this);
1860 this.doFocus.defer(50, this);
1864 doFocus : function(){
1866 this.focusEl.focus();
1871 * Hides this menu and optionally all parent menus
1872 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1874 hide : function(deep){
1876 this.hideMenuItems();
1877 if(this.el && this.isVisible()){
1878 this.fireEvent("beforehide", this);
1879 if(this.activeItem){
1880 this.activeItem.deactivate();
1881 this.activeItem = null;
1883 this.triggerEl.removeClass('open');;
1885 this.fireEvent("hide", this);
1887 if(deep === true && this.parentMenu){
1888 this.parentMenu.hide(true);
1892 onTriggerPress : function(e)
1895 Roo.log('trigger press');
1896 //Roo.log(e.getTarget());
1897 // Roo.log(this.triggerEl.dom);
1898 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1901 if (this.isVisible()) {
1905 this.show(this.triggerEl, false, false);
1914 hideMenuItems : function()
1916 //$(backdrop).remove()
1917 Roo.select('.open',true).each(function(aa) {
1919 aa.removeClass('open');
1920 //var parent = getParent($(this))
1921 //var relatedTarget = { relatedTarget: this }
1923 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1924 //if (e.isDefaultPrevented()) return
1925 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1928 addxtypeChild : function (tree, cntr) {
1929 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1931 this.menuitems.add(comp);
1952 * @class Roo.bootstrap.MenuItem
1953 * @extends Roo.bootstrap.Component
1954 * Bootstrap MenuItem class
1955 * @cfg {String} html the menu label
1956 * @cfg {String} href the link
1957 * @cfg {Boolean} preventDefault (true | false) default true
1958 * @cfg {Boolean} isContainer (true | false) default false
1962 * Create a new MenuItem
1963 * @param {Object} config The config object
1967 Roo.bootstrap.MenuItem = function(config){
1968 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1973 * The raw click event for the entire grid.
1974 * @param {Roo.bootstrap.MenuItem} this
1975 * @param {Roo.EventObject} e
1981 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1985 preventDefault: true,
1986 isContainer : false,
1988 getAutoCreate : function(){
1990 if(this.isContainer){
1993 cls: 'dropdown-menu-item'
1999 cls: 'dropdown-menu-item',
2008 if (this.parent().type == 'treeview') {
2009 cfg.cls = 'treeview-menu';
2012 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2013 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2017 initEvents: function() {
2019 //this.el.select('a').on('click', this.onClick, this);
2022 onClick : function(e)
2024 Roo.log('item on click ');
2025 //if(this.preventDefault){
2026 // e.preventDefault();
2028 //this.parent().hideMenuItems();
2030 this.fireEvent('click', this, e);
2049 * @class Roo.bootstrap.MenuSeparator
2050 * @extends Roo.bootstrap.Component
2051 * Bootstrap MenuSeparator class
2054 * Create a new MenuItem
2055 * @param {Object} config The config object
2059 Roo.bootstrap.MenuSeparator = function(config){
2060 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2063 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2065 getAutoCreate : function(){
2084 * @class Roo.bootstrap.Modal
2085 * @extends Roo.bootstrap.Component
2086 * Bootstrap Modal class
2087 * @cfg {String} title Title of dialog
2088 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2089 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2090 * @cfg {Boolean} specificTitle default false
2091 * @cfg {Array} buttons Array of buttons or standard button set..
2092 * @cfg {String} buttonPosition (left|right|center) default right
2093 * @cfg {Boolean} animate default true
2094 * @cfg {Boolean} allow_close default true
2097 * Create a new Modal Dialog
2098 * @param {Object} config The config object
2101 Roo.bootstrap.Modal = function(config){
2102 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2107 * The raw btnclick event for the button
2108 * @param {Roo.EventObject} e
2112 this.buttons = this.buttons || [];
2115 this.tmpl = Roo.factory(this.tmpl);
2120 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2122 title : 'test dialog',
2132 specificTitle: false,
2134 buttonPosition: 'right',
2148 onRender : function(ct, position)
2150 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2153 var cfg = Roo.apply({}, this.getAutoCreate());
2156 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2158 //if (!cfg.name.length) {
2162 cfg.cls += ' ' + this.cls;
2165 cfg.style = this.style;
2167 this.el = Roo.get(document.body).createChild(cfg, position);
2169 //var type = this.el.dom.type;
2174 if(this.tabIndex !== undefined){
2175 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2179 this.bodyEl = this.el.select('.modal-body',true).first();
2180 this.closeEl = this.el.select('.modal-header .close', true).first();
2181 this.footerEl = this.el.select('.modal-footer',true).first();
2182 this.titleEl = this.el.select('.modal-title',true).first();
2186 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2187 this.maskEl.enableDisplayMode("block");
2189 //this.el.addClass("x-dlg-modal");
2191 if (this.buttons.length) {
2192 Roo.each(this.buttons, function(bb) {
2193 b = Roo.apply({}, bb);
2194 b.xns = b.xns || Roo.bootstrap;
2195 b.xtype = b.xtype || 'Button';
2196 if (typeof(b.listeners) == 'undefined') {
2197 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2200 var btn = Roo.factory(b);
2202 btn.onRender(this.el.select('.modal-footer div').first());
2206 // render the children.
2209 if(typeof(this.items) != 'undefined'){
2210 var items = this.items;
2213 for(var i =0;i < items.length;i++) {
2214 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2218 this.items = nitems;
2220 // where are these used - they used to be body/close/footer
2224 //this.el.addClass([this.fieldClass, this.cls]);
2227 getAutoCreate : function(){
2232 html : this.html || ''
2237 cls : 'modal-title',
2241 if(this.specificTitle){
2247 if (this.allow_close) {
2258 style : 'display: none',
2261 cls: "modal-dialog",
2264 cls : "modal-content",
2267 cls : 'modal-header',
2272 cls : 'modal-footer',
2276 cls: 'btn-' + this.buttonPosition
2293 modal.cls += ' fade';
2299 getChildContainer : function() {
2304 getButtonContainer : function() {
2305 return this.el.select('.modal-footer div',true).first();
2308 initEvents : function()
2310 if (this.allow_close) {
2311 this.closeEl.on('click', this.hide, this);
2317 if (!this.rendered) {
2321 this.el.setStyle('display', 'block');
2325 (function(){ _this.el.addClass('in'); }).defer(50);
2327 this.el.addClass('in');
2330 // not sure how we can show data in here..
2332 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2335 Roo.get(document.body).addClass("x-body-masked");
2336 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2338 this.el.setStyle('zIndex', '10001');
2340 this.fireEvent('show', this);
2347 Roo.get(document.body).removeClass("x-body-masked");
2348 this.el.removeClass('in');
2352 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2354 this.el.setStyle('display', 'none');
2357 this.fireEvent('hide', this);
2360 addButton : function(str, cb)
2364 var b = Roo.apply({}, { html : str } );
2365 b.xns = b.xns || Roo.bootstrap;
2366 b.xtype = b.xtype || 'Button';
2367 if (typeof(b.listeners) == 'undefined') {
2368 b.listeners = { click : cb.createDelegate(this) };
2371 var btn = Roo.factory(b);
2373 btn.onRender(this.el.select('.modal-footer div').first());
2379 setDefaultButton : function(btn)
2381 //this.el.select('.modal-footer').()
2383 resizeTo: function(w,h)
2387 setContentSize : function(w, h)
2391 onButtonClick: function(btn,e)
2394 this.fireEvent('btnclick', btn.name, e);
2397 * Set the title of the Dialog
2398 * @param {String} str new Title
2400 setTitle: function(str) {
2401 this.titleEl.dom.innerHTML = str;
2404 * Set the body of the Dialog
2405 * @param {String} str new Title
2407 setBody: function(str) {
2408 this.bodyEl.dom.innerHTML = str;
2411 * Set the body of the Dialog using the template
2412 * @param {Obj} data - apply this data to the template and replace the body contents.
2414 applyBody: function(obj)
2417 Roo.log("Error - using apply Body without a template");
2420 this.tmpl.overwrite(this.bodyEl, obj);
2426 Roo.apply(Roo.bootstrap.Modal, {
2428 * Button config that displays a single OK button
2437 * Button config that displays Yes and No buttons
2453 * Button config that displays OK and Cancel buttons
2468 * Button config that displays Yes, No and Cancel buttons
2491 * messagebox - can be used as a replace
2495 * @class Roo.MessageBox
2496 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2500 Roo.Msg.alert('Status', 'Changes saved successfully.');
2502 // Prompt for user data:
2503 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2505 // process text value...
2509 // Show a dialog using config options:
2511 title:'Save Changes?',
2512 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2513 buttons: Roo.Msg.YESNOCANCEL,
2520 Roo.bootstrap.MessageBox = function(){
2521 var dlg, opt, mask, waitTimer;
2522 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2523 var buttons, activeTextEl, bwidth;
2527 var handleButton = function(button){
2529 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2533 var handleHide = function(){
2535 dlg.el.removeClass(opt.cls);
2538 // Roo.TaskMgr.stop(waitTimer);
2539 // waitTimer = null;
2544 var updateButtons = function(b){
2547 buttons["ok"].hide();
2548 buttons["cancel"].hide();
2549 buttons["yes"].hide();
2550 buttons["no"].hide();
2551 //dlg.footer.dom.style.display = 'none';
2554 dlg.footerEl.dom.style.display = '';
2555 for(var k in buttons){
2556 if(typeof buttons[k] != "function"){
2559 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2560 width += buttons[k].el.getWidth()+15;
2570 var handleEsc = function(d, k, e){
2571 if(opt && opt.closable !== false){
2581 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2582 * @return {Roo.BasicDialog} The BasicDialog element
2584 getDialog : function(){
2586 dlg = new Roo.bootstrap.Modal( {
2589 //constraintoviewport:false,
2591 //collapsible : false,
2596 //buttonAlign:"center",
2597 closeClick : function(){
2598 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2601 handleButton("cancel");
2606 dlg.on("hide", handleHide);
2608 //dlg.addKeyListener(27, handleEsc);
2610 this.buttons = buttons;
2611 var bt = this.buttonText;
2612 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2613 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2614 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2615 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2617 bodyEl = dlg.bodyEl.createChild({
2619 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2620 '<textarea class="roo-mb-textarea"></textarea>' +
2621 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2623 msgEl = bodyEl.dom.firstChild;
2624 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2625 textboxEl.enableDisplayMode();
2626 textboxEl.addKeyListener([10,13], function(){
2627 if(dlg.isVisible() && opt && opt.buttons){
2630 }else if(opt.buttons.yes){
2631 handleButton("yes");
2635 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2636 textareaEl.enableDisplayMode();
2637 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2638 progressEl.enableDisplayMode();
2639 var pf = progressEl.dom.firstChild;
2641 pp = Roo.get(pf.firstChild);
2642 pp.setHeight(pf.offsetHeight);
2650 * Updates the message box body text
2651 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2652 * the XHTML-compliant non-breaking space character '&#160;')
2653 * @return {Roo.MessageBox} This message box
2655 updateText : function(text){
2656 if(!dlg.isVisible() && !opt.width){
2657 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2659 msgEl.innerHTML = text || ' ';
2661 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2662 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2664 Math.min(opt.width || cw , this.maxWidth),
2665 Math.max(opt.minWidth || this.minWidth, bwidth)
2668 activeTextEl.setWidth(w);
2670 if(dlg.isVisible()){
2671 dlg.fixedcenter = false;
2673 // to big, make it scroll. = But as usual stupid IE does not support
2676 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2677 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2678 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2680 bodyEl.dom.style.height = '';
2681 bodyEl.dom.style.overflowY = '';
2684 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2686 bodyEl.dom.style.overflowX = '';
2689 dlg.setContentSize(w, bodyEl.getHeight());
2690 if(dlg.isVisible()){
2691 dlg.fixedcenter = true;
2697 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2698 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2699 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2700 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2701 * @return {Roo.MessageBox} This message box
2703 updateProgress : function(value, text){
2705 this.updateText(text);
2707 if (pp) { // weird bug on my firefox - for some reason this is not defined
2708 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2714 * Returns true if the message box is currently displayed
2715 * @return {Boolean} True if the message box is visible, else false
2717 isVisible : function(){
2718 return dlg && dlg.isVisible();
2722 * Hides the message box if it is displayed
2725 if(this.isVisible()){
2731 * Displays a new message box, or reinitializes an existing message box, based on the config options
2732 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2733 * The following config object properties are supported:
2735 Property Type Description
2736 ---------- --------------- ------------------------------------------------------------------------------------
2737 animEl String/Element An id or Element from which the message box should animate as it opens and
2738 closes (defaults to undefined)
2739 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2740 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2741 closable Boolean False to hide the top-right close button (defaults to true). Note that
2742 progress and wait dialogs will ignore this property and always hide the
2743 close button as they can only be closed programmatically.
2744 cls String A custom CSS class to apply to the message box element
2745 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2746 displayed (defaults to 75)
2747 fn Function A callback function to execute after closing the dialog. The arguments to the
2748 function will be btn (the name of the button that was clicked, if applicable,
2749 e.g. "ok"), and text (the value of the active text field, if applicable).
2750 Progress and wait dialogs will ignore this option since they do not respond to
2751 user actions and can only be closed programmatically, so any required function
2752 should be called by the same code after it closes the dialog.
2753 icon String A CSS class that provides a background image to be used as an icon for
2754 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2755 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2756 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2757 modal Boolean False to allow user interaction with the page while the message box is
2758 displayed (defaults to true)
2759 msg String A string that will replace the existing message box body text (defaults
2760 to the XHTML-compliant non-breaking space character ' ')
2761 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2762 progress Boolean True to display a progress bar (defaults to false)
2763 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2764 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2765 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2766 title String The title text
2767 value String The string value to set into the active textbox element if displayed
2768 wait Boolean True to display a progress bar (defaults to false)
2769 width Number The width of the dialog in pixels
2776 msg: 'Please enter your address:',
2778 buttons: Roo.MessageBox.OKCANCEL,
2781 animEl: 'addAddressBtn'
2784 * @param {Object} config Configuration options
2785 * @return {Roo.MessageBox} This message box
2787 show : function(options)
2790 // this causes nightmares if you show one dialog after another
2791 // especially on callbacks..
2793 if(this.isVisible()){
2796 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2797 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2798 Roo.log("New Dialog Message:" + options.msg )
2799 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2800 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2803 var d = this.getDialog();
2805 d.setTitle(opt.title || " ");
2806 d.closeEl.setDisplayed(opt.closable !== false);
2807 activeTextEl = textboxEl;
2808 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2813 textareaEl.setHeight(typeof opt.multiline == "number" ?
2814 opt.multiline : this.defaultTextHeight);
2815 activeTextEl = textareaEl;
2824 progressEl.setDisplayed(opt.progress === true);
2825 this.updateProgress(0);
2826 activeTextEl.dom.value = opt.value || "";
2828 dlg.setDefaultButton(activeTextEl);
2830 var bs = opt.buttons;
2834 }else if(bs && bs.yes){
2835 db = buttons["yes"];
2837 dlg.setDefaultButton(db);
2839 bwidth = updateButtons(opt.buttons);
2840 this.updateText(opt.msg);
2842 d.el.addClass(opt.cls);
2844 d.proxyDrag = opt.proxyDrag === true;
2845 d.modal = opt.modal !== false;
2846 d.mask = opt.modal !== false ? mask : false;
2848 // force it to the end of the z-index stack so it gets a cursor in FF
2849 document.body.appendChild(dlg.el.dom);
2850 d.animateTarget = null;
2851 d.show(options.animEl);
2857 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2858 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2859 * and closing the message box when the process is complete.
2860 * @param {String} title The title bar text
2861 * @param {String} msg The message box body text
2862 * @return {Roo.MessageBox} This message box
2864 progress : function(title, msg){
2871 minWidth: this.minProgressWidth,
2878 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2879 * If a callback function is passed it will be called after the user clicks the button, and the
2880 * id of the button that was clicked will be passed as the only parameter to the callback
2881 * (could also be the top-right close button).
2882 * @param {String} title The title bar text
2883 * @param {String} msg The message box body text
2884 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2885 * @param {Object} scope (optional) The scope of the callback function
2886 * @return {Roo.MessageBox} This message box
2888 alert : function(title, msg, fn, scope){
2901 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2902 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2903 * You are responsible for closing the message box when the process is complete.
2904 * @param {String} msg The message box body text
2905 * @param {String} title (optional) The title bar text
2906 * @return {Roo.MessageBox} This message box
2908 wait : function(msg, title){
2919 waitTimer = Roo.TaskMgr.start({
2921 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2929 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2930 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2931 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2932 * @param {String} title The title bar text
2933 * @param {String} msg The message box body text
2934 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2935 * @param {Object} scope (optional) The scope of the callback function
2936 * @return {Roo.MessageBox} This message box
2938 confirm : function(title, msg, fn, scope){
2942 buttons: this.YESNO,
2951 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2952 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2953 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2954 * (could also be the top-right close button) and the text that was entered will be passed as the two
2955 * parameters to the callback.
2956 * @param {String} title The title bar text
2957 * @param {String} msg The message box body text
2958 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2959 * @param {Object} scope (optional) The scope of the callback function
2960 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2961 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2962 * @return {Roo.MessageBox} This message box
2964 prompt : function(title, msg, fn, scope, multiline){
2968 buttons: this.OKCANCEL,
2973 multiline: multiline,
2980 * Button config that displays a single OK button
2985 * Button config that displays Yes and No buttons
2988 YESNO : {yes:true, no:true},
2990 * Button config that displays OK and Cancel buttons
2993 OKCANCEL : {ok:true, cancel:true},
2995 * Button config that displays Yes, No and Cancel buttons
2998 YESNOCANCEL : {yes:true, no:true, cancel:true},
3001 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3004 defaultTextHeight : 75,
3006 * The maximum width in pixels of the message box (defaults to 600)
3011 * The minimum width in pixels of the message box (defaults to 100)
3016 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3017 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3020 minProgressWidth : 250,
3022 * An object containing the default button text strings that can be overriden for localized language support.
3023 * Supported properties are: ok, cancel, yes and no.
3024 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3037 * Shorthand for {@link Roo.MessageBox}
3039 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3040 Roo.Msg = Roo.Msg || Roo.MessageBox;
3049 * @class Roo.bootstrap.Navbar
3050 * @extends Roo.bootstrap.Component
3051 * Bootstrap Navbar class
3054 * Create a new Navbar
3055 * @param {Object} config The config object
3059 Roo.bootstrap.Navbar = function(config){
3060 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3064 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3073 getAutoCreate : function(){
3076 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3080 initEvents :function ()
3082 //Roo.log(this.el.select('.navbar-toggle',true));
3083 this.el.select('.navbar-toggle',true).on('click', function() {
3084 // Roo.log('click');
3085 this.el.select('.navbar-collapse',true).toggleClass('in');
3093 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3095 var size = this.el.getSize();
3096 this.maskEl.setSize(size.width, size.height);
3097 this.maskEl.enableDisplayMode("block");
3106 getChildContainer : function()
3108 if (this.el.select('.collapse').getCount()) {
3109 return this.el.select('.collapse',true).first();
3142 * @class Roo.bootstrap.NavSimplebar
3143 * @extends Roo.bootstrap.Navbar
3144 * Bootstrap Sidebar class
3146 * @cfg {Boolean} inverse is inverted color
3148 * @cfg {String} type (nav | pills | tabs)
3149 * @cfg {Boolean} arrangement stacked | justified
3150 * @cfg {String} align (left | right) alignment
3152 * @cfg {Boolean} main (true|false) main nav bar? default false
3153 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3155 * @cfg {String} tag (header|footer|nav|div) default is nav
3161 * Create a new Sidebar
3162 * @param {Object} config The config object
3166 Roo.bootstrap.NavSimplebar = function(config){
3167 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3170 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3186 getAutoCreate : function(){
3190 tag : this.tag || 'div',
3203 this.type = this.type || 'nav';
3204 if (['tabs','pills'].indexOf(this.type)!==-1) {
3205 cfg.cn[0].cls += ' nav-' + this.type
3209 if (this.type!=='nav') {
3210 Roo.log('nav type must be nav/tabs/pills')
3212 cfg.cn[0].cls += ' navbar-nav'
3218 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3219 cfg.cn[0].cls += ' nav-' + this.arrangement;
3223 if (this.align === 'right') {
3224 cfg.cn[0].cls += ' navbar-right';
3228 cfg.cls += ' navbar-inverse';
3255 * @class Roo.bootstrap.NavHeaderbar
3256 * @extends Roo.bootstrap.NavSimplebar
3257 * Bootstrap Sidebar class
3259 * @cfg {String} brand what is brand
3260 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3261 * @cfg {String} brand_href href of the brand
3262 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3263 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3264 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3265 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3268 * Create a new Sidebar
3269 * @param {Object} config The config object
3273 Roo.bootstrap.NavHeaderbar = function(config){
3274 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3278 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3285 desktopCenter : false,
3288 getAutoCreate : function(){
3291 tag: this.nav || 'nav',
3298 if (this.desktopCenter) {
3299 cn.push({cls : 'container', cn : []});
3306 cls: 'navbar-header',
3311 cls: 'navbar-toggle',
3312 'data-toggle': 'collapse',
3317 html: 'Toggle navigation'
3339 cls: 'collapse navbar-collapse',
3343 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3345 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3346 cfg.cls += ' navbar-' + this.position;
3348 // tag can override this..
3350 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3353 if (this.brand !== '') {
3356 href: this.brand_href ? this.brand_href : '#',
3357 cls: 'navbar-brand',
3365 cfg.cls += ' main-nav';
3373 getHeaderChildContainer : function()
3375 if (this.el.select('.navbar-header').getCount()) {
3376 return this.el.select('.navbar-header',true).first();
3379 return this.getChildContainer();
3383 initEvents : function()
3385 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3387 if (this.autohide) {
3392 Roo.get(document).on('scroll',function(e) {
3393 var ns = Roo.get(document).getScroll().top;
3394 var os = prevScroll;
3398 ft.removeClass('slideDown');
3399 ft.addClass('slideUp');
3402 ft.removeClass('slideUp');
3403 ft.addClass('slideDown');
3427 * @class Roo.bootstrap.NavSidebar
3428 * @extends Roo.bootstrap.Navbar
3429 * Bootstrap Sidebar class
3432 * Create a new Sidebar
3433 * @param {Object} config The config object
3437 Roo.bootstrap.NavSidebar = function(config){
3438 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3441 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3443 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3445 getAutoCreate : function(){
3450 cls: 'sidebar sidebar-nav'
3472 * @class Roo.bootstrap.NavGroup
3473 * @extends Roo.bootstrap.Component
3474 * Bootstrap NavGroup class
3475 * @cfg {String} align left | right
3476 * @cfg {Boolean} inverse false | true
3477 * @cfg {String} type (nav|pills|tab) default nav
3478 * @cfg {String} navId - reference Id for navbar.
3482 * Create a new nav group
3483 * @param {Object} config The config object
3486 Roo.bootstrap.NavGroup = function(config){
3487 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3490 Roo.bootstrap.NavGroup.register(this);
3494 * Fires when the active item changes
3495 * @param {Roo.bootstrap.NavGroup} this
3496 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3497 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3504 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3515 getAutoCreate : function()
3517 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3524 if (['tabs','pills'].indexOf(this.type)!==-1) {
3525 cfg.cls += ' nav-' + this.type
3527 if (this.type!=='nav') {
3528 Roo.log('nav type must be nav/tabs/pills')
3530 cfg.cls += ' navbar-nav'
3533 if (this.parent().sidebar) {
3536 cls: 'dashboard-menu sidebar-menu'
3542 if (this.form === true) {
3548 if (this.align === 'right') {
3549 cfg.cls += ' navbar-right';
3551 cfg.cls += ' navbar-left';
3555 if (this.align === 'right') {
3556 cfg.cls += ' navbar-right';
3560 cfg.cls += ' navbar-inverse';
3568 * sets the active Navigation item
3569 * @param {Roo.bootstrap.NavItem} the new current navitem
3571 setActiveItem : function(item)
3574 Roo.each(this.navItems, function(v){
3579 v.setActive(false, true);
3586 item.setActive(true, true);
3587 this.fireEvent('changed', this, item, prev);
3592 * gets the active Navigation item
3593 * @return {Roo.bootstrap.NavItem} the current navitem
3595 getActive : function()
3599 Roo.each(this.navItems, function(v){
3610 indexOfNav : function()
3614 Roo.each(this.navItems, function(v,i){
3625 * adds a Navigation item
3626 * @param {Roo.bootstrap.NavItem} the navitem to add
3628 addItem : function(cfg)
3630 var cn = new Roo.bootstrap.NavItem(cfg);
3632 cn.parentId = this.id;
3633 cn.onRender(this.el, null);
3637 * register a Navigation item
3638 * @param {Roo.bootstrap.NavItem} the navitem to add
3640 register : function(item)
3642 this.navItems.push( item);
3643 item.navId = this.navId;
3648 * clear all the Navigation item
3651 clearAll : function()
3654 this.el.dom.innerHTML = '';
3657 getNavItem: function(tabId)
3660 Roo.each(this.navItems, function(e) {
3661 if (e.tabId == tabId) {
3671 setActiveNext : function()
3673 var i = this.indexOfNav(this.getActive());
3674 if (i > this.navItems.length) {
3677 this.setActiveItem(this.navItems[i+1]);
3679 setActivePrev : function()
3681 var i = this.indexOfNav(this.getActive());
3685 this.setActiveItem(this.navItems[i-1]);
3687 clearWasActive : function(except) {
3688 Roo.each(this.navItems, function(e) {
3689 if (e.tabId != except.tabId && e.was_active) {
3690 e.was_active = false;
3697 getWasActive : function ()
3700 Roo.each(this.navItems, function(e) {
3715 Roo.apply(Roo.bootstrap.NavGroup, {
3719 * register a Navigation Group
3720 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3722 register : function(navgrp)
3724 this.groups[navgrp.navId] = navgrp;
3728 * fetch a Navigation Group based on the navigation ID
3729 * @param {string} the navgroup to add
3730 * @returns {Roo.bootstrap.NavGroup} the navgroup
3732 get: function(navId) {
3733 if (typeof(this.groups[navId]) == 'undefined') {
3735 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3737 return this.groups[navId] ;
3752 * @class Roo.bootstrap.NavItem
3753 * @extends Roo.bootstrap.Component
3754 * Bootstrap Navbar.NavItem class
3755 * @cfg {String} href link to
3756 * @cfg {String} html content of button
3757 * @cfg {String} badge text inside badge
3758 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3759 * @cfg {String} glyphicon name of glyphicon
3760 * @cfg {String} icon name of font awesome icon
3761 * @cfg {Boolean} active Is item active
3762 * @cfg {Boolean} disabled Is item disabled
3764 * @cfg {Boolean} preventDefault (true | false) default false
3765 * @cfg {String} tabId the tab that this item activates.
3766 * @cfg {String} tagtype (a|span) render as a href or span?
3767 * @cfg {Boolean} animateRef (true|false) link to element default false
3770 * Create a new Navbar Item
3771 * @param {Object} config The config object
3773 Roo.bootstrap.NavItem = function(config){
3774 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3779 * The raw click event for the entire grid.
3780 * @param {Roo.EventObject} e
3785 * Fires when the active item active state changes
3786 * @param {Roo.bootstrap.NavItem} this
3787 * @param {boolean} state the new state
3793 * Fires when scroll to element
3794 * @param {Roo.bootstrap.NavItem} this
3795 * @param {Object} options
3796 * @param {Roo.EventObject} e
3804 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3812 preventDefault : false,
3819 getAutoCreate : function(){
3827 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3829 if (this.disabled) {
3830 cfg.cls += ' disabled';
3833 if (this.href || this.html || this.glyphicon || this.icon) {
3837 href : this.href || "#",
3838 html: this.html || ''
3843 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3846 if(this.glyphicon) {
3847 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3852 cfg.cn[0].html += " <span class='caret'></span>";
3856 if (this.badge !== '') {
3858 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3866 initEvents: function()
3868 if (typeof (this.menu) != 'undefined') {
3869 this.menu.parentType = this.xtype;
3870 this.menu.triggerEl = this.el;
3871 this.menu = this.addxtype(Roo.apply({}, this.menu));
3874 this.el.select('a',true).on('click', this.onClick, this);
3876 if(this.tagtype == 'span'){
3877 this.el.select('span',true).on('click', this.onClick, this);
3880 // at this point parent should be available..
3881 this.parent().register(this);
3884 onClick : function(e)
3887 this.preventDefault ||
3889 (this.animateRef && this.href.charAt(0) == '#')
3894 if (this.disabled) {
3898 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3899 if (tg && tg.transition) {
3900 Roo.log("waiting for the transitionend");
3904 Roo.log("fire event clicked");
3905 if(this.fireEvent('click', this, e) === false){
3909 if(this.tagtype == 'span'){
3913 if(this.animateRef && this.href.charAt(0) == '#'){
3914 this.scrollToElement(e);
3918 var p = this.parent();
3919 if (['tabs','pills'].indexOf(p.type)!==-1) {
3920 if (typeof(p.setActiveItem) !== 'undefined') {
3921 p.setActiveItem(this);
3924 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3925 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3926 // remove the collapsed menu expand...
3927 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3932 isActive: function () {
3935 setActive : function(state, fire, is_was_active)
3937 if (this.active && !state & this.navId) {
3938 this.was_active = true;
3939 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3941 nv.clearWasActive(this);
3945 this.active = state;
3948 this.el.removeClass('active');
3949 } else if (!this.el.hasClass('active')) {
3950 this.el.addClass('active');
3953 this.fireEvent('changed', this, state);
3956 // show a panel if it's registered and related..
3958 if (!this.navId || !this.tabId || !state || is_was_active) {
3962 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3966 var pan = tg.getPanelByName(this.tabId);
3970 // if we can not flip to new panel - go back to old nav highlight..
3971 if (false == tg.showPanel(pan)) {
3972 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3974 var onav = nv.getWasActive();
3976 onav.setActive(true, false, true);
3985 // this should not be here...
3986 setDisabled : function(state)
3988 this.disabled = state;
3990 this.el.removeClass('disabled');
3991 } else if (!this.el.hasClass('disabled')) {
3992 this.el.addClass('disabled');
3998 * Fetch the element to display the tooltip on.
3999 * @return {Roo.Element} defaults to this.el
4001 tooltipEl : function()
4003 return this.el.select('' + this.tagtype + '', true).first();
4006 scrollToElement : function(e)
4008 var c = document.body;
4010 var target = Roo.get(c).select('a[name=' + this.href.replace('#', '') +']', true).first();
4016 var o = target.calcOffsetsTo(c);
4023 this.fireEvent('scrollto', this, options, e);
4025 Roo.get(c).scrollTo('top', options.value, true);
4038 * <span> icon </span>
4039 * <span> text </span>
4040 * <span>badge </span>
4044 * @class Roo.bootstrap.NavSidebarItem
4045 * @extends Roo.bootstrap.NavItem
4046 * Bootstrap Navbar.NavSidebarItem class
4048 * Create a new Navbar Button
4049 * @param {Object} config The config object
4051 Roo.bootstrap.NavSidebarItem = function(config){
4052 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4057 * The raw click event for the entire grid.
4058 * @param {Roo.EventObject} e
4063 * Fires when the active item active state changes
4064 * @param {Roo.bootstrap.NavSidebarItem} this
4065 * @param {boolean} state the new state
4073 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4076 getAutoCreate : function(){
4081 href : this.href || '#',
4093 html : this.html || ''
4098 cfg.cls += ' active';
4102 if (this.glyphicon || this.icon) {
4103 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4104 a.cn.push({ tag : 'i', cls : c }) ;
4109 if (this.badge !== '') {
4110 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4114 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4115 a.cls += 'dropdown-toggle treeview' ;
4139 * @class Roo.bootstrap.Row
4140 * @extends Roo.bootstrap.Component
4141 * Bootstrap Row class (contains columns...)
4145 * @param {Object} config The config object
4148 Roo.bootstrap.Row = function(config){
4149 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4152 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4154 getAutoCreate : function(){
4173 * @class Roo.bootstrap.Element
4174 * @extends Roo.bootstrap.Component
4175 * Bootstrap Element class
4176 * @cfg {String} html contents of the element
4177 * @cfg {String} tag tag of the element
4178 * @cfg {String} cls class of the element
4181 * Create a new Element
4182 * @param {Object} config The config object
4185 Roo.bootstrap.Element = function(config){
4186 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4189 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4196 getAutoCreate : function(){
4209 getValue : function()
4211 return this.el.dom.innerHTML;
4214 setValue : function(value)
4216 this.el.dom.innerHTML = value;
4231 * @class Roo.bootstrap.Pagination
4232 * @extends Roo.bootstrap.Component
4233 * Bootstrap Pagination class
4234 * @cfg {String} size xs | sm | md | lg
4235 * @cfg {Boolean} inverse false | true
4238 * Create a new Pagination
4239 * @param {Object} config The config object
4242 Roo.bootstrap.Pagination = function(config){
4243 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4246 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4252 getAutoCreate : function(){
4258 cfg.cls += ' inverse';
4264 cfg.cls += " " + this.cls;
4282 * @class Roo.bootstrap.PaginationItem
4283 * @extends Roo.bootstrap.Component
4284 * Bootstrap PaginationItem class
4285 * @cfg {String} html text
4286 * @cfg {String} href the link
4287 * @cfg {Boolean} preventDefault (true | false) default true
4288 * @cfg {Boolean} active (true | false) default false
4289 * @cfg {Boolean} disabled default false
4293 * Create a new PaginationItem
4294 * @param {Object} config The config object
4298 Roo.bootstrap.PaginationItem = function(config){
4299 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4304 * The raw click event for the entire grid.
4305 * @param {Roo.EventObject} e
4311 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4315 preventDefault: true,
4320 getAutoCreate : function(){
4326 href : this.href ? this.href : '#',
4327 html : this.html ? this.html : ''
4337 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4341 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4347 initEvents: function() {
4349 this.el.on('click', this.onClick, this);
4352 onClick : function(e)
4354 Roo.log('PaginationItem on click ');
4355 if(this.preventDefault){
4363 this.fireEvent('click', this, e);
4379 * @class Roo.bootstrap.Slider
4380 * @extends Roo.bootstrap.Component
4381 * Bootstrap Slider class
4384 * Create a new Slider
4385 * @param {Object} config The config object
4388 Roo.bootstrap.Slider = function(config){
4389 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4392 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4394 getAutoCreate : function(){
4398 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4402 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4414 * Ext JS Library 1.1.1
4415 * Copyright(c) 2006-2007, Ext JS, LLC.
4417 * Originally Released Under LGPL - original licence link has changed is not relivant.
4420 * <script type="text/javascript">
4425 * @class Roo.grid.ColumnModel
4426 * @extends Roo.util.Observable
4427 * This is the default implementation of a ColumnModel used by the Grid. It defines
4428 * the columns in the grid.
4431 var colModel = new Roo.grid.ColumnModel([
4432 {header: "Ticker", width: 60, sortable: true, locked: true},
4433 {header: "Company Name", width: 150, sortable: true},
4434 {header: "Market Cap.", width: 100, sortable: true},
4435 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4436 {header: "Employees", width: 100, sortable: true, resizable: false}
4441 * The config options listed for this class are options which may appear in each
4442 * individual column definition.
4443 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4445 * @param {Object} config An Array of column config objects. See this class's
4446 * config objects for details.
4448 Roo.grid.ColumnModel = function(config){
4450 * The config passed into the constructor
4452 this.config = config;
4455 // if no id, create one
4456 // if the column does not have a dataIndex mapping,
4457 // map it to the order it is in the config
4458 for(var i = 0, len = config.length; i < len; i++){
4460 if(typeof c.dataIndex == "undefined"){
4463 if(typeof c.renderer == "string"){
4464 c.renderer = Roo.util.Format[c.renderer];
4466 if(typeof c.id == "undefined"){
4469 if(c.editor && c.editor.xtype){
4470 c.editor = Roo.factory(c.editor, Roo.grid);
4472 if(c.editor && c.editor.isFormField){
4473 c.editor = new Roo.grid.GridEditor(c.editor);
4475 this.lookup[c.id] = c;
4479 * The width of columns which have no width specified (defaults to 100)
4482 this.defaultWidth = 100;
4485 * Default sortable of columns which have no sortable specified (defaults to false)
4488 this.defaultSortable = false;
4492 * @event widthchange
4493 * Fires when the width of a column changes.
4494 * @param {ColumnModel} this
4495 * @param {Number} columnIndex The column index
4496 * @param {Number} newWidth The new width
4498 "widthchange": true,
4500 * @event headerchange
4501 * Fires when the text of a header changes.
4502 * @param {ColumnModel} this
4503 * @param {Number} columnIndex The column index
4504 * @param {Number} newText The new header text
4506 "headerchange": true,
4508 * @event hiddenchange
4509 * Fires when a column is hidden or "unhidden".
4510 * @param {ColumnModel} this
4511 * @param {Number} columnIndex The column index
4512 * @param {Boolean} hidden true if hidden, false otherwise
4514 "hiddenchange": true,
4516 * @event columnmoved
4517 * Fires when a column is moved.
4518 * @param {ColumnModel} this
4519 * @param {Number} oldIndex
4520 * @param {Number} newIndex
4522 "columnmoved" : true,
4524 * @event columlockchange
4525 * Fires when a column's locked state is changed
4526 * @param {ColumnModel} this
4527 * @param {Number} colIndex
4528 * @param {Boolean} locked true if locked
4530 "columnlockchange" : true
4532 Roo.grid.ColumnModel.superclass.constructor.call(this);
4534 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4536 * @cfg {String} header The header text to display in the Grid view.
4539 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4540 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4541 * specified, the column's index is used as an index into the Record's data Array.
4544 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4545 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4548 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4549 * Defaults to the value of the {@link #defaultSortable} property.
4550 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4553 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4556 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4559 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4562 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4565 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4566 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4567 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4568 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4571 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4574 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4577 * @cfg {String} cursor (Optional)
4580 * @cfg {String} tooltip (Optional)
4583 * Returns the id of the column at the specified index.
4584 * @param {Number} index The column index
4585 * @return {String} the id
4587 getColumnId : function(index){
4588 return this.config[index].id;
4592 * Returns the column for a specified id.
4593 * @param {String} id The column id
4594 * @return {Object} the column
4596 getColumnById : function(id){
4597 return this.lookup[id];
4602 * Returns the column for a specified dataIndex.
4603 * @param {String} dataIndex The column dataIndex
4604 * @return {Object|Boolean} the column or false if not found
4606 getColumnByDataIndex: function(dataIndex){
4607 var index = this.findColumnIndex(dataIndex);
4608 return index > -1 ? this.config[index] : false;
4612 * Returns the index for a specified column id.
4613 * @param {String} id The column id
4614 * @return {Number} the index, or -1 if not found
4616 getIndexById : function(id){
4617 for(var i = 0, len = this.config.length; i < len; i++){
4618 if(this.config[i].id == id){
4626 * Returns the index for a specified column dataIndex.
4627 * @param {String} dataIndex The column dataIndex
4628 * @return {Number} the index, or -1 if not found
4631 findColumnIndex : function(dataIndex){
4632 for(var i = 0, len = this.config.length; i < len; i++){
4633 if(this.config[i].dataIndex == dataIndex){
4641 moveColumn : function(oldIndex, newIndex){
4642 var c = this.config[oldIndex];
4643 this.config.splice(oldIndex, 1);
4644 this.config.splice(newIndex, 0, c);
4645 this.dataMap = null;
4646 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4649 isLocked : function(colIndex){
4650 return this.config[colIndex].locked === true;
4653 setLocked : function(colIndex, value, suppressEvent){
4654 if(this.isLocked(colIndex) == value){
4657 this.config[colIndex].locked = value;
4659 this.fireEvent("columnlockchange", this, colIndex, value);
4663 getTotalLockedWidth : function(){
4665 for(var i = 0; i < this.config.length; i++){
4666 if(this.isLocked(i) && !this.isHidden(i)){
4667 this.totalWidth += this.getColumnWidth(i);
4673 getLockedCount : function(){
4674 for(var i = 0, len = this.config.length; i < len; i++){
4675 if(!this.isLocked(i)){
4682 * Returns the number of columns.
4685 getColumnCount : function(visibleOnly){
4686 if(visibleOnly === true){
4688 for(var i = 0, len = this.config.length; i < len; i++){
4689 if(!this.isHidden(i)){
4695 return this.config.length;
4699 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4700 * @param {Function} fn
4701 * @param {Object} scope (optional)
4702 * @return {Array} result
4704 getColumnsBy : function(fn, scope){
4706 for(var i = 0, len = this.config.length; i < len; i++){
4707 var c = this.config[i];
4708 if(fn.call(scope||this, c, i) === true){
4716 * Returns true if the specified column is sortable.
4717 * @param {Number} col The column index
4720 isSortable : function(col){
4721 if(typeof this.config[col].sortable == "undefined"){
4722 return this.defaultSortable;
4724 return this.config[col].sortable;
4728 * Returns the rendering (formatting) function defined for the column.
4729 * @param {Number} col The column index.
4730 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4732 getRenderer : function(col){
4733 if(!this.config[col].renderer){
4734 return Roo.grid.ColumnModel.defaultRenderer;
4736 return this.config[col].renderer;
4740 * Sets the rendering (formatting) function for a column.
4741 * @param {Number} col The column index
4742 * @param {Function} fn The function to use to process the cell's raw data
4743 * to return HTML markup for the grid view. The render function is called with
4744 * the following parameters:<ul>
4745 * <li>Data value.</li>
4746 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4747 * <li>css A CSS style string to apply to the table cell.</li>
4748 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4749 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4750 * <li>Row index</li>
4751 * <li>Column index</li>
4752 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4754 setRenderer : function(col, fn){
4755 this.config[col].renderer = fn;
4759 * Returns the width for the specified column.
4760 * @param {Number} col The column index
4763 getColumnWidth : function(col){
4764 return this.config[col].width * 1 || this.defaultWidth;
4768 * Sets the width for a column.
4769 * @param {Number} col The column index
4770 * @param {Number} width The new width
4772 setColumnWidth : function(col, width, suppressEvent){
4773 this.config[col].width = width;
4774 this.totalWidth = null;
4776 this.fireEvent("widthchange", this, col, width);
4781 * Returns the total width of all columns.
4782 * @param {Boolean} includeHidden True to include hidden column widths
4785 getTotalWidth : function(includeHidden){
4786 if(!this.totalWidth){
4787 this.totalWidth = 0;
4788 for(var i = 0, len = this.config.length; i < len; i++){
4789 if(includeHidden || !this.isHidden(i)){
4790 this.totalWidth += this.getColumnWidth(i);
4794 return this.totalWidth;
4798 * Returns the header for the specified column.
4799 * @param {Number} col The column index
4802 getColumnHeader : function(col){
4803 return this.config[col].header;
4807 * Sets the header for a column.
4808 * @param {Number} col The column index
4809 * @param {String} header The new header
4811 setColumnHeader : function(col, header){
4812 this.config[col].header = header;
4813 this.fireEvent("headerchange", this, col, header);
4817 * Returns the tooltip for the specified column.
4818 * @param {Number} col The column index
4821 getColumnTooltip : function(col){
4822 return this.config[col].tooltip;
4825 * Sets the tooltip for a column.
4826 * @param {Number} col The column index
4827 * @param {String} tooltip The new tooltip
4829 setColumnTooltip : function(col, tooltip){
4830 this.config[col].tooltip = tooltip;
4834 * Returns the dataIndex for the specified column.
4835 * @param {Number} col The column index
4838 getDataIndex : function(col){
4839 return this.config[col].dataIndex;
4843 * Sets the dataIndex for a column.
4844 * @param {Number} col The column index
4845 * @param {Number} dataIndex The new dataIndex
4847 setDataIndex : function(col, dataIndex){
4848 this.config[col].dataIndex = dataIndex;
4854 * Returns true if the cell is editable.
4855 * @param {Number} colIndex The column index
4856 * @param {Number} rowIndex The row index
4859 isCellEditable : function(colIndex, rowIndex){
4860 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4864 * Returns the editor defined for the cell/column.
4865 * return false or null to disable editing.
4866 * @param {Number} colIndex The column index
4867 * @param {Number} rowIndex The row index
4870 getCellEditor : function(colIndex, rowIndex){
4871 return this.config[colIndex].editor;
4875 * Sets if a column is editable.
4876 * @param {Number} col The column index
4877 * @param {Boolean} editable True if the column is editable
4879 setEditable : function(col, editable){
4880 this.config[col].editable = editable;
4885 * Returns true if the column is hidden.
4886 * @param {Number} colIndex The column index
4889 isHidden : function(colIndex){
4890 return this.config[colIndex].hidden;
4895 * Returns true if the column width cannot be changed
4897 isFixed : function(colIndex){
4898 return this.config[colIndex].fixed;
4902 * Returns true if the column can be resized
4905 isResizable : function(colIndex){
4906 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4909 * Sets if a column is hidden.
4910 * @param {Number} colIndex The column index
4911 * @param {Boolean} hidden True if the column is hidden
4913 setHidden : function(colIndex, hidden){
4914 this.config[colIndex].hidden = hidden;
4915 this.totalWidth = null;
4916 this.fireEvent("hiddenchange", this, colIndex, hidden);
4920 * Sets the editor for a column.
4921 * @param {Number} col The column index
4922 * @param {Object} editor The editor object
4924 setEditor : function(col, editor){
4925 this.config[col].editor = editor;
4929 Roo.grid.ColumnModel.defaultRenderer = function(value){
4930 if(typeof value == "string" && value.length < 1){
4936 // Alias for backwards compatibility
4937 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4940 * Ext JS Library 1.1.1
4941 * Copyright(c) 2006-2007, Ext JS, LLC.
4943 * Originally Released Under LGPL - original licence link has changed is not relivant.
4946 * <script type="text/javascript">
4950 * @class Roo.LoadMask
4951 * A simple utility class for generically masking elements while loading data. If the element being masked has
4952 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4953 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4954 * element's UpdateManager load indicator and will be destroyed after the initial load.
4956 * Create a new LoadMask
4957 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4958 * @param {Object} config The config object
4960 Roo.LoadMask = function(el, config){
4961 this.el = Roo.get(el);
4962 Roo.apply(this, config);
4964 this.store.on('beforeload', this.onBeforeLoad, this);
4965 this.store.on('load', this.onLoad, this);
4966 this.store.on('loadexception', this.onLoadException, this);
4967 this.removeMask = false;
4969 var um = this.el.getUpdateManager();
4970 um.showLoadIndicator = false; // disable the default indicator
4971 um.on('beforeupdate', this.onBeforeLoad, this);
4972 um.on('update', this.onLoad, this);
4973 um.on('failure', this.onLoad, this);
4974 this.removeMask = true;
4978 Roo.LoadMask.prototype = {
4980 * @cfg {Boolean} removeMask
4981 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4982 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4986 * The text to display in a centered loading message box (defaults to 'Loading...')
4990 * @cfg {String} msgCls
4991 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4993 msgCls : 'x-mask-loading',
4996 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5002 * Disables the mask to prevent it from being displayed
5004 disable : function(){
5005 this.disabled = true;
5009 * Enables the mask so that it can be displayed
5011 enable : function(){
5012 this.disabled = false;
5015 onLoadException : function()
5019 if (typeof(arguments[3]) != 'undefined') {
5020 Roo.MessageBox.alert("Error loading",arguments[3]);
5024 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5025 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5034 this.el.unmask(this.removeMask);
5039 this.el.unmask(this.removeMask);
5043 onBeforeLoad : function(){
5045 this.el.mask(this.msg, this.msgCls);
5050 destroy : function(){
5052 this.store.un('beforeload', this.onBeforeLoad, this);
5053 this.store.un('load', this.onLoad, this);
5054 this.store.un('loadexception', this.onLoadException, this);
5056 var um = this.el.getUpdateManager();
5057 um.un('beforeupdate', this.onBeforeLoad, this);
5058 um.un('update', this.onLoad, this);
5059 um.un('failure', this.onLoad, this);
5070 * @class Roo.bootstrap.Table
5071 * @extends Roo.bootstrap.Component
5072 * Bootstrap Table class
5073 * @cfg {String} cls table class
5074 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5075 * @cfg {String} bgcolor Specifies the background color for a table
5076 * @cfg {Number} border Specifies whether the table cells should have borders or not
5077 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5078 * @cfg {Number} cellspacing Specifies the space between cells
5079 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5080 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5081 * @cfg {String} sortable Specifies that the table should be sortable
5082 * @cfg {String} summary Specifies a summary of the content of a table
5083 * @cfg {Number} width Specifies the width of a table
5084 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5086 * @cfg {boolean} striped Should the rows be alternative striped
5087 * @cfg {boolean} bordered Add borders to the table
5088 * @cfg {boolean} hover Add hover highlighting
5089 * @cfg {boolean} condensed Format condensed
5090 * @cfg {boolean} responsive Format condensed
5091 * @cfg {Boolean} loadMask (true|false) default false
5092 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5093 * @cfg {Boolean} thead (true|false) generate thead, default true
5094 * @cfg {Boolean} RowSelection (true|false) default false
5095 * @cfg {Boolean} CellSelection (true|false) default false
5096 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5100 * Create a new Table
5101 * @param {Object} config The config object
5104 Roo.bootstrap.Table = function(config){
5105 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5108 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5109 this.sm = this.selModel;
5110 this.sm.xmodule = this.xmodule || false;
5112 if (this.cm && typeof(this.cm.config) == 'undefined') {
5113 this.colModel = new Roo.grid.ColumnModel(this.cm);
5114 this.cm = this.colModel;
5115 this.cm.xmodule = this.xmodule || false;
5118 this.store= Roo.factory(this.store, Roo.data);
5119 this.ds = this.store;
5120 this.ds.xmodule = this.xmodule || false;
5123 if (this.footer && this.store) {
5124 this.footer.dataSource = this.ds;
5125 this.footer = Roo.factory(this.footer);
5132 * Fires when a cell is clicked
5133 * @param {Roo.bootstrap.Table} this
5134 * @param {Roo.Element} el
5135 * @param {Number} rowIndex
5136 * @param {Number} columnIndex
5137 * @param {Roo.EventObject} e
5141 * @event celldblclick
5142 * Fires when a cell is double clicked
5143 * @param {Roo.bootstrap.Table} this
5144 * @param {Roo.Element} el
5145 * @param {Number} rowIndex
5146 * @param {Number} columnIndex
5147 * @param {Roo.EventObject} e
5149 "celldblclick" : true,
5152 * Fires when a row is clicked
5153 * @param {Roo.bootstrap.Table} this
5154 * @param {Roo.Element} el
5155 * @param {Number} rowIndex
5156 * @param {Roo.EventObject} e
5160 * @event rowdblclick
5161 * Fires when a row is double clicked
5162 * @param {Roo.bootstrap.Table} this
5163 * @param {Roo.Element} el
5164 * @param {Number} rowIndex
5165 * @param {Roo.EventObject} e
5167 "rowdblclick" : true,
5170 * Fires when a mouseover occur
5171 * @param {Roo.bootstrap.Table} this
5172 * @param {Roo.Element} el
5173 * @param {Number} rowIndex
5174 * @param {Number} columnIndex
5175 * @param {Roo.EventObject} e
5180 * Fires when a mouseout occur
5181 * @param {Roo.bootstrap.Table} this
5182 * @param {Roo.Element} el
5183 * @param {Number} rowIndex
5184 * @param {Number} columnIndex
5185 * @param {Roo.EventObject} e
5190 * Fires when a row is rendered, so you can change add a style to it.
5191 * @param {Roo.bootstrap.Table} this
5192 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5196 * @event rowsrendered
5197 * Fires when all the rows have been rendered
5198 * @param {Roo.bootstrap.Table} this
5200 'rowsrendered' : true
5205 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5229 RowSelection : false,
5230 CellSelection : false,
5233 // Roo.Element - the tbody
5236 getAutoCreate : function(){
5237 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5246 cfg.cls += ' table-striped';
5250 cfg.cls += ' table-hover';
5252 if (this.bordered) {
5253 cfg.cls += ' table-bordered';
5255 if (this.condensed) {
5256 cfg.cls += ' table-condensed';
5258 if (this.responsive) {
5259 cfg.cls += ' table-responsive';
5263 cfg.cls+= ' ' +this.cls;
5266 // this lot should be simplifed...
5269 cfg.align=this.align;
5272 cfg.bgcolor=this.bgcolor;
5275 cfg.border=this.border;
5277 if (this.cellpadding) {
5278 cfg.cellpadding=this.cellpadding;
5280 if (this.cellspacing) {
5281 cfg.cellspacing=this.cellspacing;
5284 cfg.frame=this.frame;
5287 cfg.rules=this.rules;
5289 if (this.sortable) {
5290 cfg.sortable=this.sortable;
5293 cfg.summary=this.summary;
5296 cfg.width=this.width;
5299 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5302 if(this.store || this.cm){
5304 cfg.cn.push(this.renderHeader());
5307 cfg.cn.push(this.renderBody());
5310 cfg.cn.push(this.renderFooter());
5313 cfg.cls+= ' TableGrid';
5316 return { cn : [ cfg ] };
5319 initEvents : function()
5321 if(!this.store || !this.cm){
5325 //Roo.log('initEvents with ds!!!!');
5327 this.mainBody = this.el.select('tbody', true).first();
5332 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5333 e.on('click', _this.sort, _this);
5336 this.el.on("click", this.onClick, this);
5337 this.el.on("dblclick", this.onDblClick, this);
5339 // why is this done????? = it breaks dialogs??
5340 //this.parent().el.setStyle('position', 'relative');
5344 this.footer.parentId = this.id;
5345 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5348 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5350 this.store.on('load', this.onLoad, this);
5351 this.store.on('beforeload', this.onBeforeLoad, this);
5352 this.store.on('update', this.onUpdate, this);
5353 this.store.on('add', this.onAdd, this);
5357 onMouseover : function(e, el)
5359 var cell = Roo.get(el);
5365 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5366 cell = cell.findParent('td', false, true);
5369 var row = cell.findParent('tr', false, true);
5370 var cellIndex = cell.dom.cellIndex;
5371 var rowIndex = row.dom.rowIndex - 1; // start from 0
5373 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5377 onMouseout : function(e, el)
5379 var cell = Roo.get(el);
5385 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5386 cell = cell.findParent('td', false, true);
5389 var row = cell.findParent('tr', false, true);
5390 var cellIndex = cell.dom.cellIndex;
5391 var rowIndex = row.dom.rowIndex - 1; // start from 0
5393 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5397 onClick : function(e, el)
5399 var cell = Roo.get(el);
5401 if(!cell || (!this.CellSelection && !this.RowSelection)){
5405 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5406 cell = cell.findParent('td', false, true);
5409 if(!cell || typeof(cell) == 'undefined'){
5413 var row = cell.findParent('tr', false, true);
5415 if(!row || typeof(row) == 'undefined'){
5419 var cellIndex = cell.dom.cellIndex;
5420 var rowIndex = this.getRowIndex(row);
5422 if(this.CellSelection){
5423 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5426 if(this.RowSelection){
5427 this.fireEvent('rowclick', this, row, rowIndex, e);
5433 onDblClick : function(e,el)
5435 var cell = Roo.get(el);
5437 if(!cell || (!this.CellSelection && !this.RowSelection)){
5441 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5442 cell = cell.findParent('td', false, true);
5445 if(!cell || typeof(cell) == 'undefined'){
5449 var row = cell.findParent('tr', false, true);
5451 if(!row || typeof(row) == 'undefined'){
5455 var cellIndex = cell.dom.cellIndex;
5456 var rowIndex = this.getRowIndex(row);
5458 if(this.CellSelection){
5459 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5462 if(this.RowSelection){
5463 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5467 sort : function(e,el)
5469 var col = Roo.get(el);
5471 if(!col.hasClass('sortable')){
5475 var sort = col.attr('sort');
5478 if(col.hasClass('glyphicon-arrow-up')){
5482 this.store.sortInfo = {field : sort, direction : dir};
5485 Roo.log("calling footer first");
5486 this.footer.onClick('first');
5489 this.store.load({ params : { start : 0 } });
5493 renderHeader : function()
5502 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5504 var config = cm.config[i];
5509 html: cm.getColumnHeader(i)
5512 if(typeof(config.tooltip) != 'undefined'){
5513 c.tooltip = config.tooltip;
5516 if(typeof(config.colspan) != 'undefined'){
5517 c.colspan = config.colspan;
5520 if(typeof(config.hidden) != 'undefined' && config.hidden){
5521 c.style += ' display:none;';
5524 if(typeof(config.dataIndex) != 'undefined'){
5525 c.sort = config.dataIndex;
5528 if(typeof(config.sortable) != 'undefined' && config.sortable){
5532 if(typeof(config.align) != 'undefined' && config.align.length){
5533 c.style += ' text-align:' + config.align + ';';
5536 if(typeof(config.width) != 'undefined'){
5537 c.style += ' width:' + config.width + 'px;';
5546 renderBody : function()
5556 colspan : this.cm.getColumnCount()
5566 renderFooter : function()
5576 colspan : this.cm.getColumnCount()
5590 Roo.log('ds onload');
5595 var ds = this.store;
5597 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5598 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5600 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5601 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5604 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5605 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5609 var tbody = this.mainBody;
5611 if(ds.getCount() > 0){
5612 ds.data.each(function(d,rowIndex){
5613 var row = this.renderRow(cm, ds, rowIndex);
5615 tbody.createChild(row);
5619 if(row.cellObjects.length){
5620 Roo.each(row.cellObjects, function(r){
5621 _this.renderCellObject(r);
5628 Roo.each(this.el.select('tbody td', true).elements, function(e){
5629 e.on('mouseover', _this.onMouseover, _this);
5632 Roo.each(this.el.select('tbody td', true).elements, function(e){
5633 e.on('mouseout', _this.onMouseout, _this);
5635 this.fireEvent('rowsrendered', this);
5636 //if(this.loadMask){
5637 // this.maskEl.hide();
5642 onUpdate : function(ds,record)
5644 this.refreshRow(record);
5647 onRemove : function(ds, record, index, isUpdate){
5648 if(isUpdate !== true){
5649 this.fireEvent("beforerowremoved", this, index, record);
5651 var bt = this.mainBody.dom;
5653 var rows = this.el.select('tbody > tr', true).elements;
5655 if(typeof(rows[index]) != 'undefined'){
5656 bt.removeChild(rows[index].dom);
5659 // if(bt.rows[index]){
5660 // bt.removeChild(bt.rows[index]);
5663 if(isUpdate !== true){
5664 //this.stripeRows(index);
5665 //this.syncRowHeights(index, index);
5667 this.fireEvent("rowremoved", this, index, record);
5671 onAdd : function(ds, records, rowIndex)
5673 //Roo.log('on Add called');
5674 // - note this does not handle multiple adding very well..
5675 var bt = this.mainBody.dom;
5676 for (var i =0 ; i < records.length;i++) {
5677 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5678 //Roo.log(records[i]);
5679 //Roo.log(this.store.getAt(rowIndex+i));
5680 this.insertRow(this.store, rowIndex + i, false);
5687 refreshRow : function(record){
5688 var ds = this.store, index;
5689 if(typeof record == 'number'){
5691 record = ds.getAt(index);
5693 index = ds.indexOf(record);
5695 this.insertRow(ds, index, true);
5696 this.onRemove(ds, record, index+1, true);
5697 //this.syncRowHeights(index, index);
5699 this.fireEvent("rowupdated", this, index, record);
5702 insertRow : function(dm, rowIndex, isUpdate){
5705 this.fireEvent("beforerowsinserted", this, rowIndex);
5707 //var s = this.getScrollState();
5708 var row = this.renderRow(this.cm, this.store, rowIndex);
5709 // insert before rowIndex..
5710 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5714 if(row.cellObjects.length){
5715 Roo.each(row.cellObjects, function(r){
5716 _this.renderCellObject(r);
5721 this.fireEvent("rowsinserted", this, rowIndex);
5722 //this.syncRowHeights(firstRow, lastRow);
5723 //this.stripeRows(firstRow);
5730 getRowDom : function(rowIndex)
5732 var rows = this.el.select('tbody > tr', true).elements;
5734 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5737 // returns the object tree for a tr..
5740 renderRow : function(cm, ds, rowIndex)
5743 var d = ds.getAt(rowIndex);
5750 var cellObjects = [];
5752 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5753 var config = cm.config[i];
5755 var renderer = cm.getRenderer(i);
5759 if(typeof(renderer) !== 'undefined'){
5760 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5762 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5763 // and are rendered into the cells after the row is rendered - using the id for the element.
5765 if(typeof(value) === 'object'){
5775 rowIndex : rowIndex,
5780 this.fireEvent('rowclass', this, rowcfg);
5784 cls : rowcfg.rowClass,
5786 html: (typeof(value) === 'object') ? '' : value
5793 if(typeof(config.colspan) != 'undefined'){
5794 td.colspan = config.colspan;
5797 if(typeof(config.hidden) != 'undefined' && config.hidden){
5798 td.style += ' display:none;';
5801 if(typeof(config.align) != 'undefined' && config.align.length){
5802 td.style += ' text-align:' + config.align + ';';
5805 if(typeof(config.width) != 'undefined'){
5806 td.style += ' width:' + config.width + 'px;';
5809 if(typeof(config.cursor) != 'undefined'){
5810 td.style += ' cursor:' + config.cursor + ';';
5817 row.cellObjects = cellObjects;
5825 onBeforeLoad : function()
5827 //Roo.log('ds onBeforeLoad');
5831 //if(this.loadMask){
5832 // this.maskEl.show();
5840 this.el.select('tbody', true).first().dom.innerHTML = '';
5843 * Show or hide a row.
5844 * @param {Number} rowIndex to show or hide
5845 * @param {Boolean} state hide
5847 setRowVisibility : function(rowIndex, state)
5849 var bt = this.mainBody.dom;
5851 var rows = this.el.select('tbody > tr', true).elements;
5853 if(typeof(rows[rowIndex]) == 'undefined'){
5856 rows[rowIndex].dom.style.display = state ? '' : 'none';
5860 getSelectionModel : function(){
5862 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5864 return this.selModel;
5867 * Render the Roo.bootstrap object from renderder
5869 renderCellObject : function(r)
5873 var t = r.cfg.render(r.container);
5876 Roo.each(r.cfg.cn, function(c){
5878 container: t.getChildContainer(),
5881 _this.renderCellObject(child);
5886 getRowIndex : function(row)
5890 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5913 * @class Roo.bootstrap.TableCell
5914 * @extends Roo.bootstrap.Component
5915 * Bootstrap TableCell class
5916 * @cfg {String} html cell contain text
5917 * @cfg {String} cls cell class
5918 * @cfg {String} tag cell tag (td|th) default td
5919 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5920 * @cfg {String} align Aligns the content in a cell
5921 * @cfg {String} axis Categorizes cells
5922 * @cfg {String} bgcolor Specifies the background color of a cell
5923 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5924 * @cfg {Number} colspan Specifies the number of columns a cell should span
5925 * @cfg {String} headers Specifies one or more header cells a cell is related to
5926 * @cfg {Number} height Sets the height of a cell
5927 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5928 * @cfg {Number} rowspan Sets the number of rows a cell should span
5929 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5930 * @cfg {String} valign Vertical aligns the content in a cell
5931 * @cfg {Number} width Specifies the width of a cell
5934 * Create a new TableCell
5935 * @param {Object} config The config object
5938 Roo.bootstrap.TableCell = function(config){
5939 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5942 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5962 getAutoCreate : function(){
5963 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5983 cfg.align=this.align
5989 cfg.bgcolor=this.bgcolor
5992 cfg.charoff=this.charoff
5995 cfg.colspan=this.colspan
5998 cfg.headers=this.headers
6001 cfg.height=this.height
6004 cfg.nowrap=this.nowrap
6007 cfg.rowspan=this.rowspan
6010 cfg.scope=this.scope
6013 cfg.valign=this.valign
6016 cfg.width=this.width
6035 * @class Roo.bootstrap.TableRow
6036 * @extends Roo.bootstrap.Component
6037 * Bootstrap TableRow class
6038 * @cfg {String} cls row class
6039 * @cfg {String} align Aligns the content in a table row
6040 * @cfg {String} bgcolor Specifies a background color for a table row
6041 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6042 * @cfg {String} valign Vertical aligns the content in a table row
6045 * Create a new TableRow
6046 * @param {Object} config The config object
6049 Roo.bootstrap.TableRow = function(config){
6050 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6053 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6061 getAutoCreate : function(){
6062 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6072 cfg.align = this.align;
6075 cfg.bgcolor = this.bgcolor;
6078 cfg.charoff = this.charoff;
6081 cfg.valign = this.valign;
6099 * @class Roo.bootstrap.TableBody
6100 * @extends Roo.bootstrap.Component
6101 * Bootstrap TableBody class
6102 * @cfg {String} cls element class
6103 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6104 * @cfg {String} align Aligns the content inside the element
6105 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6106 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6109 * Create a new TableBody
6110 * @param {Object} config The config object
6113 Roo.bootstrap.TableBody = function(config){
6114 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6117 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6125 getAutoCreate : function(){
6126 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6140 cfg.align = this.align;
6143 cfg.charoff = this.charoff;
6146 cfg.valign = this.valign;
6153 // initEvents : function()
6160 // this.store = Roo.factory(this.store, Roo.data);
6161 // this.store.on('load', this.onLoad, this);
6163 // this.store.load();
6167 // onLoad: function ()
6169 // this.fireEvent('load', this);
6179 * Ext JS Library 1.1.1
6180 * Copyright(c) 2006-2007, Ext JS, LLC.
6182 * Originally Released Under LGPL - original licence link has changed is not relivant.
6185 * <script type="text/javascript">
6188 // as we use this in bootstrap.
6189 Roo.namespace('Roo.form');
6191 * @class Roo.form.Action
6192 * Internal Class used to handle form actions
6194 * @param {Roo.form.BasicForm} el The form element or its id
6195 * @param {Object} config Configuration options
6200 // define the action interface
6201 Roo.form.Action = function(form, options){
6203 this.options = options || {};
6206 * Client Validation Failed
6209 Roo.form.Action.CLIENT_INVALID = 'client';
6211 * Server Validation Failed
6214 Roo.form.Action.SERVER_INVALID = 'server';
6216 * Connect to Server Failed
6219 Roo.form.Action.CONNECT_FAILURE = 'connect';
6221 * Reading Data from Server Failed
6224 Roo.form.Action.LOAD_FAILURE = 'load';
6226 Roo.form.Action.prototype = {
6228 failureType : undefined,
6229 response : undefined,
6233 run : function(options){
6238 success : function(response){
6243 handleResponse : function(response){
6247 // default connection failure
6248 failure : function(response){
6250 this.response = response;
6251 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6252 this.form.afterAction(this, false);
6255 processResponse : function(response){
6256 this.response = response;
6257 if(!response.responseText){
6260 this.result = this.handleResponse(response);
6264 // utility functions used internally
6265 getUrl : function(appendParams){
6266 var url = this.options.url || this.form.url || this.form.el.dom.action;
6268 var p = this.getParams();
6270 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6276 getMethod : function(){
6277 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6280 getParams : function(){
6281 var bp = this.form.baseParams;
6282 var p = this.options.params;
6284 if(typeof p == "object"){
6285 p = Roo.urlEncode(Roo.applyIf(p, bp));
6286 }else if(typeof p == 'string' && bp){
6287 p += '&' + Roo.urlEncode(bp);
6290 p = Roo.urlEncode(bp);
6295 createCallback : function(){
6297 success: this.success,
6298 failure: this.failure,
6300 timeout: (this.form.timeout*1000),
6301 upload: this.form.fileUpload ? this.success : undefined
6306 Roo.form.Action.Submit = function(form, options){
6307 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6310 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6313 haveProgress : false,
6314 uploadComplete : false,
6316 // uploadProgress indicator.
6317 uploadProgress : function()
6319 if (!this.form.progressUrl) {
6323 if (!this.haveProgress) {
6324 Roo.MessageBox.progress("Uploading", "Uploading");
6326 if (this.uploadComplete) {
6327 Roo.MessageBox.hide();
6331 this.haveProgress = true;
6333 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6335 var c = new Roo.data.Connection();
6337 url : this.form.progressUrl,
6342 success : function(req){
6343 //console.log(data);
6347 rdata = Roo.decode(req.responseText)
6349 Roo.log("Invalid data from server..");
6353 if (!rdata || !rdata.success) {
6355 Roo.MessageBox.alert(Roo.encode(rdata));
6358 var data = rdata.data;
6360 if (this.uploadComplete) {
6361 Roo.MessageBox.hide();
6366 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6367 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6370 this.uploadProgress.defer(2000,this);
6373 failure: function(data) {
6374 Roo.log('progress url failed ');
6385 // run get Values on the form, so it syncs any secondary forms.
6386 this.form.getValues();
6388 var o = this.options;
6389 var method = this.getMethod();
6390 var isPost = method == 'POST';
6391 if(o.clientValidation === false || this.form.isValid()){
6393 if (this.form.progressUrl) {
6394 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6395 (new Date() * 1) + '' + Math.random());
6400 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6401 form:this.form.el.dom,
6402 url:this.getUrl(!isPost),
6404 params:isPost ? this.getParams() : null,
6405 isUpload: this.form.fileUpload
6408 this.uploadProgress();
6410 }else if (o.clientValidation !== false){ // client validation failed
6411 this.failureType = Roo.form.Action.CLIENT_INVALID;
6412 this.form.afterAction(this, false);
6416 success : function(response)
6418 this.uploadComplete= true;
6419 if (this.haveProgress) {
6420 Roo.MessageBox.hide();
6424 var result = this.processResponse(response);
6425 if(result === true || result.success){
6426 this.form.afterAction(this, true);
6430 this.form.markInvalid(result.errors);
6431 this.failureType = Roo.form.Action.SERVER_INVALID;
6433 this.form.afterAction(this, false);
6435 failure : function(response)
6437 this.uploadComplete= true;
6438 if (this.haveProgress) {
6439 Roo.MessageBox.hide();
6442 this.response = response;
6443 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6444 this.form.afterAction(this, false);
6447 handleResponse : function(response){
6448 if(this.form.errorReader){
6449 var rs = this.form.errorReader.read(response);
6452 for(var i = 0, len = rs.records.length; i < len; i++) {
6453 var r = rs.records[i];
6457 if(errors.length < 1){
6461 success : rs.success,
6467 ret = Roo.decode(response.responseText);
6471 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6481 Roo.form.Action.Load = function(form, options){
6482 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6483 this.reader = this.form.reader;
6486 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6491 Roo.Ajax.request(Roo.apply(
6492 this.createCallback(), {
6493 method:this.getMethod(),
6494 url:this.getUrl(false),
6495 params:this.getParams()
6499 success : function(response){
6501 var result = this.processResponse(response);
6502 if(result === true || !result.success || !result.data){
6503 this.failureType = Roo.form.Action.LOAD_FAILURE;
6504 this.form.afterAction(this, false);
6507 this.form.clearInvalid();
6508 this.form.setValues(result.data);
6509 this.form.afterAction(this, true);
6512 handleResponse : function(response){
6513 if(this.form.reader){
6514 var rs = this.form.reader.read(response);
6515 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6517 success : rs.success,
6521 return Roo.decode(response.responseText);
6525 Roo.form.Action.ACTION_TYPES = {
6526 'load' : Roo.form.Action.Load,
6527 'submit' : Roo.form.Action.Submit
6536 * @class Roo.bootstrap.Form
6537 * @extends Roo.bootstrap.Component
6538 * Bootstrap Form class
6539 * @cfg {String} method GET | POST (default POST)
6540 * @cfg {String} labelAlign top | left (default top)
6541 * @cfg {String} align left | right - for navbars
6542 * @cfg {Boolean} loadMask load mask when submit (default true)
6547 * @param {Object} config The config object
6551 Roo.bootstrap.Form = function(config){
6552 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6555 * @event clientvalidation
6556 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6557 * @param {Form} this
6558 * @param {Boolean} valid true if the form has passed client-side validation
6560 clientvalidation: true,
6562 * @event beforeaction
6563 * Fires before any action is performed. Return false to cancel the action.
6564 * @param {Form} this
6565 * @param {Action} action The action to be performed
6569 * @event actionfailed
6570 * Fires when an action fails.
6571 * @param {Form} this
6572 * @param {Action} action The action that failed
6574 actionfailed : true,
6576 * @event actioncomplete
6577 * Fires when an action is completed.
6578 * @param {Form} this
6579 * @param {Action} action The action that completed
6581 actioncomplete : true
6586 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6589 * @cfg {String} method
6590 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6595 * The URL to use for form actions if one isn't supplied in the action options.
6598 * @cfg {Boolean} fileUpload
6599 * Set to true if this form is a file upload.
6603 * @cfg {Object} baseParams
6604 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6608 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6612 * @cfg {Sting} align (left|right) for navbar forms
6617 activeAction : null,
6620 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6621 * element by passing it or its id or mask the form itself by passing in true.
6624 waitMsgTarget : false,
6628 getAutoCreate : function(){
6632 method : this.method || 'POST',
6633 id : this.id || Roo.id(),
6636 if (this.parent().xtype.match(/^Nav/)) {
6637 cfg.cls = 'navbar-form navbar-' + this.align;
6641 if (this.labelAlign == 'left' ) {
6642 cfg.cls += ' form-horizontal';
6648 initEvents : function()
6650 this.el.on('submit', this.onSubmit, this);
6651 // this was added as random key presses on the form where triggering form submit.
6652 this.el.on('keypress', function(e) {
6653 if (e.getCharCode() != 13) {
6656 // we might need to allow it for textareas.. and some other items.
6657 // check e.getTarget().
6659 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6663 Roo.log("keypress blocked");
6671 onSubmit : function(e){
6676 * Returns true if client-side validation on the form is successful.
6679 isValid : function(){
6680 var items = this.getItems();
6682 items.each(function(f){
6691 * Returns true if any fields in this form have changed since their original load.
6694 isDirty : function(){
6696 var items = this.getItems();
6697 items.each(function(f){
6707 * Performs a predefined action (submit or load) or custom actions you define on this form.
6708 * @param {String} actionName The name of the action type
6709 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6710 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6711 * accept other config options):
6713 Property Type Description
6714 ---------------- --------------- ----------------------------------------------------------------------------------
6715 url String The url for the action (defaults to the form's url)
6716 method String The form method to use (defaults to the form's method, or POST if not defined)
6717 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6718 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6719 validate the form on the client (defaults to false)
6721 * @return {BasicForm} this
6723 doAction : function(action, options){
6724 if(typeof action == 'string'){
6725 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6727 if(this.fireEvent('beforeaction', this, action) !== false){
6728 this.beforeAction(action);
6729 action.run.defer(100, action);
6735 beforeAction : function(action){
6736 var o = action.options;
6739 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6741 // not really supported yet.. ??
6743 //if(this.waitMsgTarget === true){
6744 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6745 //}else if(this.waitMsgTarget){
6746 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6747 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6749 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6755 afterAction : function(action, success){
6756 this.activeAction = null;
6757 var o = action.options;
6759 //if(this.waitMsgTarget === true){
6761 //}else if(this.waitMsgTarget){
6762 // this.waitMsgTarget.unmask();
6764 // Roo.MessageBox.updateProgress(1);
6765 // Roo.MessageBox.hide();
6772 Roo.callback(o.success, o.scope, [this, action]);
6773 this.fireEvent('actioncomplete', this, action);
6777 // failure condition..
6778 // we have a scenario where updates need confirming.
6779 // eg. if a locking scenario exists..
6780 // we look for { errors : { needs_confirm : true }} in the response.
6782 (typeof(action.result) != 'undefined') &&
6783 (typeof(action.result.errors) != 'undefined') &&
6784 (typeof(action.result.errors.needs_confirm) != 'undefined')
6787 Roo.log("not supported yet");
6790 Roo.MessageBox.confirm(
6791 "Change requires confirmation",
6792 action.result.errorMsg,
6797 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6807 Roo.callback(o.failure, o.scope, [this, action]);
6808 // show an error message if no failed handler is set..
6809 if (!this.hasListener('actionfailed')) {
6810 Roo.log("need to add dialog support");
6812 Roo.MessageBox.alert("Error",
6813 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6814 action.result.errorMsg :
6815 "Saving Failed, please check your entries or try again"
6820 this.fireEvent('actionfailed', this, action);
6825 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6826 * @param {String} id The value to search for
6829 findField : function(id){
6830 var items = this.getItems();
6831 var field = items.get(id);
6833 items.each(function(f){
6834 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6841 return field || null;
6844 * Mark fields in this form invalid in bulk.
6845 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6846 * @return {BasicForm} this
6848 markInvalid : function(errors){
6849 if(errors instanceof Array){
6850 for(var i = 0, len = errors.length; i < len; i++){
6851 var fieldError = errors[i];
6852 var f = this.findField(fieldError.id);
6854 f.markInvalid(fieldError.msg);
6860 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6861 field.markInvalid(errors[id]);
6865 //Roo.each(this.childForms || [], function (f) {
6866 // f.markInvalid(errors);
6873 * Set values for fields in this form in bulk.
6874 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6875 * @return {BasicForm} this
6877 setValues : function(values){
6878 if(values instanceof Array){ // array of objects
6879 for(var i = 0, len = values.length; i < len; i++){
6881 var f = this.findField(v.id);
6883 f.setValue(v.value);
6884 if(this.trackResetOnLoad){
6885 f.originalValue = f.getValue();
6889 }else{ // object hash
6892 if(typeof values[id] != 'function' && (field = this.findField(id))){
6894 if (field.setFromData &&
6896 field.displayField &&
6897 // combos' with local stores can
6898 // be queried via setValue()
6899 // to set their value..
6900 (field.store && !field.store.isLocal)
6904 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6905 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6906 field.setFromData(sd);
6909 field.setValue(values[id]);
6913 if(this.trackResetOnLoad){
6914 field.originalValue = field.getValue();
6920 //Roo.each(this.childForms || [], function (f) {
6921 // f.setValues(values);
6928 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6929 * they are returned as an array.
6930 * @param {Boolean} asString
6933 getValues : function(asString){
6934 //if (this.childForms) {
6935 // copy values from the child forms
6936 // Roo.each(this.childForms, function (f) {
6937 // this.setValues(f.getValues());
6943 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6944 if(asString === true){
6947 return Roo.urlDecode(fs);
6951 * Returns the fields in this form as an object with key/value pairs.
6952 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6955 getFieldValues : function(with_hidden)
6957 var items = this.getItems();
6959 items.each(function(f){
6963 var v = f.getValue();
6964 if (f.inputType =='radio') {
6965 if (typeof(ret[f.getName()]) == 'undefined') {
6966 ret[f.getName()] = ''; // empty..
6969 if (!f.el.dom.checked) {
6977 // not sure if this supported any more..
6978 if ((typeof(v) == 'object') && f.getRawValue) {
6979 v = f.getRawValue() ; // dates..
6981 // combo boxes where name != hiddenName...
6982 if (f.name != f.getName()) {
6983 ret[f.name] = f.getRawValue();
6985 ret[f.getName()] = v;
6992 * Clears all invalid messages in this form.
6993 * @return {BasicForm} this
6995 clearInvalid : function(){
6996 var items = this.getItems();
6998 items.each(function(f){
7009 * @return {BasicForm} this
7012 var items = this.getItems();
7013 items.each(function(f){
7017 Roo.each(this.childForms || [], function (f) {
7024 getItems : function()
7026 var r=new Roo.util.MixedCollection(false, function(o){
7027 return o.id || (o.id = Roo.id());
7029 var iter = function(el) {
7036 Roo.each(el.items,function(e) {
7056 * Ext JS Library 1.1.1
7057 * Copyright(c) 2006-2007, Ext JS, LLC.
7059 * Originally Released Under LGPL - original licence link has changed is not relivant.
7062 * <script type="text/javascript">
7065 * @class Roo.form.VTypes
7066 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7069 Roo.form.VTypes = function(){
7070 // closure these in so they are only created once.
7071 var alpha = /^[a-zA-Z_]+$/;
7072 var alphanum = /^[a-zA-Z0-9_]+$/;
7073 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7074 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7076 // All these messages and functions are configurable
7079 * The function used to validate email addresses
7080 * @param {String} value The email address
7082 'email' : function(v){
7083 return email.test(v);
7086 * The error text to display when the email validation function returns false
7089 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7091 * The keystroke filter mask to be applied on email input
7094 'emailMask' : /[a-z0-9_\.\-@]/i,
7097 * The function used to validate URLs
7098 * @param {String} value The URL
7100 'url' : function(v){
7104 * The error text to display when the url validation function returns false
7107 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7110 * The function used to validate alpha values
7111 * @param {String} value The value
7113 'alpha' : function(v){
7114 return alpha.test(v);
7117 * The error text to display when the alpha validation function returns false
7120 'alphaText' : 'This field should only contain letters and _',
7122 * The keystroke filter mask to be applied on alpha input
7125 'alphaMask' : /[a-z_]/i,
7128 * The function used to validate alphanumeric values
7129 * @param {String} value The value
7131 'alphanum' : function(v){
7132 return alphanum.test(v);
7135 * The error text to display when the alphanumeric validation function returns false
7138 'alphanumText' : 'This field should only contain letters, numbers and _',
7140 * The keystroke filter mask to be applied on alphanumeric input
7143 'alphanumMask' : /[a-z0-9_]/i
7153 * @class Roo.bootstrap.Input
7154 * @extends Roo.bootstrap.Component
7155 * Bootstrap Input class
7156 * @cfg {Boolean} disabled is it disabled
7157 * @cfg {String} fieldLabel - the label associated
7158 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7159 * @cfg {String} name name of the input
7160 * @cfg {string} fieldLabel - the label associated
7161 * @cfg {string} inputType - input / file submit ...
7162 * @cfg {string} placeholder - placeholder to put in text.
7163 * @cfg {string} before - input group add on before
7164 * @cfg {string} after - input group add on after
7165 * @cfg {string} size - (lg|sm) or leave empty..
7166 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7167 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7168 * @cfg {Number} md colspan out of 12 for computer-sized screens
7169 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7170 * @cfg {string} value default value of the input
7171 * @cfg {Number} labelWidth set the width of label (0-12)
7172 * @cfg {String} labelAlign (top|left)
7173 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7174 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7176 * @cfg {String} align (left|center|right) Default left
7181 * Create a new Input
7182 * @param {Object} config The config object
7185 Roo.bootstrap.Input = function(config){
7186 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7191 * Fires when this field receives input focus.
7192 * @param {Roo.form.Field} this
7197 * Fires when this field loses input focus.
7198 * @param {Roo.form.Field} this
7203 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7204 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7205 * @param {Roo.form.Field} this
7206 * @param {Roo.EventObject} e The event object
7211 * Fires just before the field blurs if the field value has changed.
7212 * @param {Roo.form.Field} this
7213 * @param {Mixed} newValue The new value
7214 * @param {Mixed} oldValue The original value
7219 * Fires after the field has been marked as invalid.
7220 * @param {Roo.form.Field} this
7221 * @param {String} msg The validation message
7226 * Fires after the field has been validated with no errors.
7227 * @param {Roo.form.Field} this
7232 * Fires after the key up
7233 * @param {Roo.form.Field} this
7234 * @param {Roo.EventObject} e The event Object
7240 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7242 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7243 automatic validation (defaults to "keyup").
7245 validationEvent : "keyup",
7247 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7249 validateOnBlur : true,
7251 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7253 validationDelay : 250,
7255 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7257 focusClass : "x-form-focus", // not needed???
7261 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7263 invalidClass : "has-warning",
7266 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7268 validClass : "has-success",
7271 * @cfg {Boolean} hasFeedback (true|false) default true
7276 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7278 invalidFeedbackClass : "glyphicon-warning-sign",
7281 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7283 validFeedbackClass : "glyphicon-ok",
7286 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7288 selectOnFocus : false,
7291 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7295 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7300 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7302 disableKeyFilter : false,
7305 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7309 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7313 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7315 blankText : "This field is required",
7318 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7322 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7324 maxLength : Number.MAX_VALUE,
7326 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7328 minLengthText : "The minimum length for this field is {0}",
7330 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7332 maxLengthText : "The maximum length for this field is {0}",
7336 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7337 * If available, this function will be called only after the basic validators all return true, and will be passed the
7338 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7342 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7343 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7344 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7348 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7352 autocomplete: false,
7371 formatedValue : false,
7373 parentLabelAlign : function()
7376 while (parent.parent()) {
7377 parent = parent.parent();
7378 if (typeof(parent.labelAlign) !='undefined') {
7379 return parent.labelAlign;
7386 getAutoCreate : function(){
7388 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7394 if(this.inputType != 'hidden'){
7395 cfg.cls = 'form-group' //input-group
7401 type : this.inputType,
7403 cls : 'form-control',
7404 placeholder : this.placeholder || '',
7405 autocomplete : this.autocomplete || 'new-password'
7410 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7413 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7414 input.maxLength = this.maxLength;
7417 if (this.disabled) {
7418 input.disabled=true;
7421 if (this.readOnly) {
7422 input.readonly=true;
7426 input.name = this.name;
7429 input.cls += ' input-' + this.size;
7432 ['xs','sm','md','lg'].map(function(size){
7433 if (settings[size]) {
7434 cfg.cls += ' col-' + size + '-' + settings[size];
7438 var inputblock = input;
7440 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7444 cls: 'glyphicon form-control-feedback'
7448 cls : 'has-feedback',
7456 // var inputblock = input;
7458 if (this.before || this.after) {
7461 cls : 'input-group',
7465 if (this.before && typeof(this.before) == 'string') {
7467 inputblock.cn.push({
7469 cls : 'roo-input-before input-group-addon',
7473 if (this.before && typeof(this.before) == 'object') {
7474 this.before = Roo.factory(this.before);
7475 Roo.log(this.before);
7476 inputblock.cn.push({
7478 cls : 'roo-input-before input-group-' +
7479 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7483 inputblock.cn.push(input);
7485 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7486 inputblock.cls += ' has-feedback';
7487 inputblock.cn.push(feedback);
7490 if (this.after && typeof(this.after) == 'string') {
7491 inputblock.cn.push({
7493 cls : 'roo-input-after input-group-addon',
7497 if (this.after && typeof(this.after) == 'object') {
7498 this.after = Roo.factory(this.after);
7499 Roo.log(this.after);
7500 inputblock.cn.push({
7502 cls : 'roo-input-after input-group-' +
7503 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7508 if (align ==='left' && this.fieldLabel.length) {
7509 Roo.log("left and has label");
7515 cls : 'control-label col-sm-' + this.labelWidth,
7516 html : this.fieldLabel
7520 cls : "col-sm-" + (12 - this.labelWidth),
7527 } else if ( this.fieldLabel.length) {
7533 //cls : 'input-group-addon',
7534 html : this.fieldLabel
7544 Roo.log(" no label && no align");
7553 Roo.log('input-parentType: ' + this.parentType);
7555 if (this.parentType === 'Navbar' && this.parent().bar) {
7556 cfg.cls += ' navbar-form';
7564 * return the real input element.
7566 inputEl: function ()
7568 return this.el.select('input.form-control',true).first();
7571 tooltipEl : function()
7573 return this.inputEl();
7576 setDisabled : function(v)
7578 var i = this.inputEl().dom;
7580 i.removeAttribute('disabled');
7584 i.setAttribute('disabled','true');
7586 initEvents : function()
7589 this.inputEl().on("keydown" , this.fireKey, this);
7590 this.inputEl().on("focus", this.onFocus, this);
7591 this.inputEl().on("blur", this.onBlur, this);
7593 this.inputEl().relayEvent('keyup', this);
7595 // reference to original value for reset
7596 this.originalValue = this.getValue();
7597 //Roo.form.TextField.superclass.initEvents.call(this);
7598 if(this.validationEvent == 'keyup'){
7599 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7600 this.inputEl().on('keyup', this.filterValidation, this);
7602 else if(this.validationEvent !== false){
7603 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7606 if(this.selectOnFocus){
7607 this.on("focus", this.preFocus, this);
7610 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7611 this.inputEl().on("keypress", this.filterKeys, this);
7614 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7615 this.el.on("click", this.autoSize, this);
7618 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7619 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7622 if (typeof(this.before) == 'object') {
7623 this.before.render(this.el.select('.roo-input-before',true).first());
7625 if (typeof(this.after) == 'object') {
7626 this.after.render(this.el.select('.roo-input-after',true).first());
7631 filterValidation : function(e){
7632 if(!e.isNavKeyPress()){
7633 this.validationTask.delay(this.validationDelay);
7637 * Validates the field value
7638 * @return {Boolean} True if the value is valid, else false
7640 validate : function(){
7641 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7642 if(this.disabled || this.validateValue(this.getRawValue())){
7653 * Validates a value according to the field's validation rules and marks the field as invalid
7654 * if the validation fails
7655 * @param {Mixed} value The value to validate
7656 * @return {Boolean} True if the value is valid, else false
7658 validateValue : function(value){
7659 if(value.length < 1) { // if it's blank
7660 if(this.allowBlank){
7666 if(value.length < this.minLength){
7669 if(value.length > this.maxLength){
7673 var vt = Roo.form.VTypes;
7674 if(!vt[this.vtype](value, this)){
7678 if(typeof this.validator == "function"){
7679 var msg = this.validator(value);
7685 if(this.regex && !this.regex.test(value)){
7695 fireKey : function(e){
7696 //Roo.log('field ' + e.getKey());
7697 if(e.isNavKeyPress()){
7698 this.fireEvent("specialkey", this, e);
7701 focus : function (selectText){
7703 this.inputEl().focus();
7704 if(selectText === true){
7705 this.inputEl().dom.select();
7711 onFocus : function(){
7712 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7713 // this.el.addClass(this.focusClass);
7716 this.hasFocus = true;
7717 this.startValue = this.getValue();
7718 this.fireEvent("focus", this);
7722 beforeBlur : Roo.emptyFn,
7726 onBlur : function(){
7728 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7729 //this.el.removeClass(this.focusClass);
7731 this.hasFocus = false;
7732 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7735 var v = this.getValue();
7736 if(String(v) !== String(this.startValue)){
7737 this.fireEvent('change', this, v, this.startValue);
7739 this.fireEvent("blur", this);
7743 * Resets the current field value to the originally loaded value and clears any validation messages
7746 this.setValue(this.originalValue);
7750 * Returns the name of the field
7751 * @return {Mixed} name The name field
7753 getName: function(){
7757 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7758 * @return {Mixed} value The field value
7760 getValue : function(){
7762 var v = this.inputEl().getValue();
7767 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7768 * @return {Mixed} value The field value
7770 getRawValue : function(){
7771 var v = this.inputEl().getValue();
7777 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7778 * @param {Mixed} value The value to set
7780 setRawValue : function(v){
7781 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7784 selectText : function(start, end){
7785 var v = this.getRawValue();
7787 start = start === undefined ? 0 : start;
7788 end = end === undefined ? v.length : end;
7789 var d = this.inputEl().dom;
7790 if(d.setSelectionRange){
7791 d.setSelectionRange(start, end);
7792 }else if(d.createTextRange){
7793 var range = d.createTextRange();
7794 range.moveStart("character", start);
7795 range.moveEnd("character", v.length-end);
7802 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7803 * @param {Mixed} value The value to set
7805 setValue : function(v){
7808 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7814 processValue : function(value){
7815 if(this.stripCharsRe){
7816 var newValue = value.replace(this.stripCharsRe, '');
7817 if(newValue !== value){
7818 this.setRawValue(newValue);
7825 preFocus : function(){
7827 if(this.selectOnFocus){
7828 this.inputEl().dom.select();
7831 filterKeys : function(e){
7833 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7836 var c = e.getCharCode(), cc = String.fromCharCode(c);
7837 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7840 if(!this.maskRe.test(cc)){
7845 * Clear any invalid styles/messages for this field
7847 clearInvalid : function(){
7849 if(!this.el || this.preventMark){ // not rendered
7852 this.el.removeClass(this.invalidClass);
7854 this.fireEvent('valid', this);
7858 * Mark this field as valid
7860 markValid : function(){
7861 if(!this.el || this.preventMark){ // not rendered
7865 this.el.removeClass([this.invalidClass, this.validClass]);
7867 if(this.disabled || this.allowBlank){
7871 this.el.addClass(this.validClass);
7873 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7875 var feedback = this.el.select('.form-control-feedback', true).first();
7878 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7879 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7884 this.fireEvent('valid', this);
7888 * Mark this field as invalid
7889 * @param {String} msg The validation message
7891 markInvalid : function(msg){
7892 if(!this.el || this.preventMark){ // not rendered
7896 this.el.removeClass([this.invalidClass, this.validClass]);
7898 if(this.disabled || this.allowBlank){
7902 this.el.addClass(this.invalidClass);
7904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7906 var feedback = this.el.select('.form-control-feedback', true).first();
7909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7911 if(this.getValue().length){
7912 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7919 this.fireEvent('invalid', this, msg);
7922 SafariOnKeyDown : function(event)
7924 // this is a workaround for a password hang bug on chrome/ webkit.
7926 var isSelectAll = false;
7928 if(this.inputEl().dom.selectionEnd > 0){
7929 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7931 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7932 event.preventDefault();
7937 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7939 event.preventDefault();
7940 // this is very hacky as keydown always get's upper case.
7942 var cc = String.fromCharCode(event.getCharCode());
7943 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7947 adjustWidth : function(tag, w){
7948 tag = tag.toLowerCase();
7949 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7950 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7954 if(tag == 'textarea'){
7957 }else if(Roo.isOpera){
7961 if(tag == 'textarea'){
7980 * @class Roo.bootstrap.TextArea
7981 * @extends Roo.bootstrap.Input
7982 * Bootstrap TextArea class
7983 * @cfg {Number} cols Specifies the visible width of a text area
7984 * @cfg {Number} rows Specifies the visible number of lines in a text area
7985 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7986 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7987 * @cfg {string} html text
7990 * Create a new TextArea
7991 * @param {Object} config The config object
7994 Roo.bootstrap.TextArea = function(config){
7995 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7999 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8009 getAutoCreate : function(){
8011 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8022 value : this.value || '',
8023 html: this.html || '',
8024 cls : 'form-control',
8025 placeholder : this.placeholder || ''
8029 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8030 input.maxLength = this.maxLength;
8034 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8038 input.cols = this.cols;
8041 if (this.readOnly) {
8042 input.readonly = true;
8046 input.name = this.name;
8050 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8054 ['xs','sm','md','lg'].map(function(size){
8055 if (settings[size]) {
8056 cfg.cls += ' col-' + size + '-' + settings[size];
8060 var inputblock = input;
8062 if(this.hasFeedback && !this.allowBlank){
8066 cls: 'glyphicon form-control-feedback'
8070 cls : 'has-feedback',
8079 if (this.before || this.after) {
8082 cls : 'input-group',
8086 inputblock.cn.push({
8088 cls : 'input-group-addon',
8093 inputblock.cn.push(input);
8095 if(this.hasFeedback && !this.allowBlank){
8096 inputblock.cls += ' has-feedback';
8097 inputblock.cn.push(feedback);
8101 inputblock.cn.push({
8103 cls : 'input-group-addon',
8110 if (align ==='left' && this.fieldLabel.length) {
8111 Roo.log("left and has label");
8117 cls : 'control-label col-sm-' + this.labelWidth,
8118 html : this.fieldLabel
8122 cls : "col-sm-" + (12 - this.labelWidth),
8129 } else if ( this.fieldLabel.length) {
8135 //cls : 'input-group-addon',
8136 html : this.fieldLabel
8146 Roo.log(" no label && no align");
8156 if (this.disabled) {
8157 input.disabled=true;
8164 * return the real textarea element.
8166 inputEl: function ()
8168 return this.el.select('textarea.form-control',true).first();
8176 * trigger field - base class for combo..
8181 * @class Roo.bootstrap.TriggerField
8182 * @extends Roo.bootstrap.Input
8183 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8184 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8185 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8186 * for which you can provide a custom implementation. For example:
8188 var trigger = new Roo.bootstrap.TriggerField();
8189 trigger.onTriggerClick = myTriggerFn;
8190 trigger.applyTo('my-field');
8193 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8194 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8195 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8196 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8197 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8200 * Create a new TriggerField.
8201 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8202 * to the base TextField)
8204 Roo.bootstrap.TriggerField = function(config){
8205 this.mimicing = false;
8206 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8209 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8211 * @cfg {String} triggerClass A CSS class to apply to the trigger
8214 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8218 /** @cfg {Boolean} grow @hide */
8219 /** @cfg {Number} growMin @hide */
8220 /** @cfg {Number} growMax @hide */
8226 autoSize: Roo.emptyFn,
8233 actionMode : 'wrap',
8238 getAutoCreate : function(){
8240 var align = this.labelAlign || this.parentLabelAlign();
8245 cls: 'form-group' //input-group
8252 type : this.inputType,
8253 cls : 'form-control',
8254 autocomplete: 'new-password',
8255 placeholder : this.placeholder || ''
8259 input.name = this.name;
8262 input.cls += ' input-' + this.size;
8265 if (this.disabled) {
8266 input.disabled=true;
8269 var inputblock = input;
8271 if(this.hasFeedback && !this.allowBlank){
8275 cls: 'glyphicon form-control-feedback'
8279 cls : 'has-feedback',
8287 if (this.before || this.after) {
8290 cls : 'input-group',
8294 inputblock.cn.push({
8296 cls : 'input-group-addon',
8301 inputblock.cn.push(input);
8303 if(this.hasFeedback && !this.allowBlank){
8304 inputblock.cls += ' has-feedback';
8305 inputblock.cn.push(feedback);
8309 inputblock.cn.push({
8311 cls : 'input-group-addon',
8324 cls: 'form-hidden-field'
8332 Roo.log('multiple');
8340 cls: 'form-hidden-field'
8344 cls: 'select2-choices',
8348 cls: 'select2-search-field',
8361 cls: 'select2-container input-group',
8366 // cls: 'typeahead typeahead-long dropdown-menu',
8367 // style: 'display:none'
8372 if(!this.multiple && this.showToggleBtn){
8378 if (this.caret != false) {
8381 cls: 'fa fa-' + this.caret
8388 cls : 'input-group-addon btn dropdown-toggle',
8393 cls: 'combobox-clear',
8407 combobox.cls += ' select2-container-multi';
8410 if (align ==='left' && this.fieldLabel.length) {
8412 Roo.log("left and has label");
8418 cls : 'control-label col-sm-' + this.labelWidth,
8419 html : this.fieldLabel
8423 cls : "col-sm-" + (12 - this.labelWidth),
8430 } else if ( this.fieldLabel.length) {
8436 //cls : 'input-group-addon',
8437 html : this.fieldLabel
8447 Roo.log(" no label && no align");
8454 ['xs','sm','md','lg'].map(function(size){
8455 if (settings[size]) {
8456 cfg.cls += ' col-' + size + '-' + settings[size];
8467 onResize : function(w, h){
8468 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8469 // if(typeof w == 'number'){
8470 // var x = w - this.trigger.getWidth();
8471 // this.inputEl().setWidth(this.adjustWidth('input', x));
8472 // this.trigger.setStyle('left', x+'px');
8477 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8480 getResizeEl : function(){
8481 return this.inputEl();
8485 getPositionEl : function(){
8486 return this.inputEl();
8490 alignErrorIcon : function(){
8491 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8495 initEvents : function(){
8499 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8500 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8501 if(!this.multiple && this.showToggleBtn){
8502 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8503 if(this.hideTrigger){
8504 this.trigger.setDisplayed(false);
8506 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8510 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8513 //this.trigger.addClassOnOver('x-form-trigger-over');
8514 //this.trigger.addClassOnClick('x-form-trigger-click');
8517 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8521 createList : function()
8523 this.list = Roo.get(document.body).createChild({
8525 cls: 'typeahead typeahead-long dropdown-menu',
8526 style: 'display:none'
8529 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8534 initTrigger : function(){
8539 onDestroy : function(){
8541 this.trigger.removeAllListeners();
8542 // this.trigger.remove();
8545 // this.wrap.remove();
8547 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8551 onFocus : function(){
8552 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8555 this.wrap.addClass('x-trigger-wrap-focus');
8556 this.mimicing = true;
8557 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8558 if(this.monitorTab){
8559 this.el.on("keydown", this.checkTab, this);
8566 checkTab : function(e){
8567 if(e.getKey() == e.TAB){
8573 onBlur : function(){
8578 mimicBlur : function(e, t){
8580 if(!this.wrap.contains(t) && this.validateBlur()){
8587 triggerBlur : function(){
8588 this.mimicing = false;
8589 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8590 if(this.monitorTab){
8591 this.el.un("keydown", this.checkTab, this);
8593 //this.wrap.removeClass('x-trigger-wrap-focus');
8594 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8598 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8599 validateBlur : function(e, t){
8604 onDisable : function(){
8605 this.inputEl().dom.disabled = true;
8606 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8608 // this.wrap.addClass('x-item-disabled');
8613 onEnable : function(){
8614 this.inputEl().dom.disabled = false;
8615 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8617 // this.el.removeClass('x-item-disabled');
8622 onShow : function(){
8623 var ae = this.getActionEl();
8626 ae.dom.style.display = '';
8627 ae.dom.style.visibility = 'visible';
8633 onHide : function(){
8634 var ae = this.getActionEl();
8635 ae.dom.style.display = 'none';
8639 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8640 * by an implementing function.
8642 * @param {EventObject} e
8644 onTriggerClick : Roo.emptyFn
8648 * Ext JS Library 1.1.1
8649 * Copyright(c) 2006-2007, Ext JS, LLC.
8651 * Originally Released Under LGPL - original licence link has changed is not relivant.
8654 * <script type="text/javascript">
8659 * @class Roo.data.SortTypes
8661 * Defines the default sorting (casting?) comparison functions used when sorting data.
8663 Roo.data.SortTypes = {
8665 * Default sort that does nothing
8666 * @param {Mixed} s The value being converted
8667 * @return {Mixed} The comparison value
8674 * The regular expression used to strip tags
8678 stripTagsRE : /<\/?[^>]+>/gi,
8681 * Strips all HTML tags to sort on text only
8682 * @param {Mixed} s The value being converted
8683 * @return {String} The comparison value
8685 asText : function(s){
8686 return String(s).replace(this.stripTagsRE, "");
8690 * Strips all HTML tags to sort on text only - Case insensitive
8691 * @param {Mixed} s The value being converted
8692 * @return {String} The comparison value
8694 asUCText : function(s){
8695 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8699 * Case insensitive string
8700 * @param {Mixed} s The value being converted
8701 * @return {String} The comparison value
8703 asUCString : function(s) {
8704 return String(s).toUpperCase();
8709 * @param {Mixed} s The value being converted
8710 * @return {Number} The comparison value
8712 asDate : function(s) {
8716 if(s instanceof Date){
8719 return Date.parse(String(s));
8724 * @param {Mixed} s The value being converted
8725 * @return {Float} The comparison value
8727 asFloat : function(s) {
8728 var val = parseFloat(String(s).replace(/,/g, ""));
8729 if(isNaN(val)) val = 0;
8735 * @param {Mixed} s The value being converted
8736 * @return {Number} The comparison value
8738 asInt : function(s) {
8739 var val = parseInt(String(s).replace(/,/g, ""));
8740 if(isNaN(val)) val = 0;
8745 * Ext JS Library 1.1.1
8746 * Copyright(c) 2006-2007, Ext JS, LLC.
8748 * Originally Released Under LGPL - original licence link has changed is not relivant.
8751 * <script type="text/javascript">
8755 * @class Roo.data.Record
8756 * Instances of this class encapsulate both record <em>definition</em> information, and record
8757 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8758 * to access Records cached in an {@link Roo.data.Store} object.<br>
8760 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8761 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8764 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8766 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8767 * {@link #create}. The parameters are the same.
8768 * @param {Array} data An associative Array of data values keyed by the field name.
8769 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8770 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8771 * not specified an integer id is generated.
8773 Roo.data.Record = function(data, id){
8774 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8779 * Generate a constructor for a specific record layout.
8780 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8781 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8782 * Each field definition object may contain the following properties: <ul>
8783 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8784 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8785 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8786 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8787 * is being used, then this is a string containing the javascript expression to reference the data relative to
8788 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8789 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8790 * this may be omitted.</p></li>
8791 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8792 * <ul><li>auto (Default, implies no conversion)</li>
8797 * <li>date</li></ul></p></li>
8798 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8799 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8800 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8801 * by the Reader into an object that will be stored in the Record. It is passed the
8802 * following parameters:<ul>
8803 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8805 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8807 * <br>usage:<br><pre><code>
8808 var TopicRecord = Roo.data.Record.create(
8809 {name: 'title', mapping: 'topic_title'},
8810 {name: 'author', mapping: 'username'},
8811 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8812 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8813 {name: 'lastPoster', mapping: 'user2'},
8814 {name: 'excerpt', mapping: 'post_text'}
8817 var myNewRecord = new TopicRecord({
8818 title: 'Do my job please',
8821 lastPost: new Date(),
8822 lastPoster: 'Animal',
8823 excerpt: 'No way dude!'
8825 myStore.add(myNewRecord);
8830 Roo.data.Record.create = function(o){
8832 f.superclass.constructor.apply(this, arguments);
8834 Roo.extend(f, Roo.data.Record);
8835 var p = f.prototype;
8836 p.fields = new Roo.util.MixedCollection(false, function(field){
8839 for(var i = 0, len = o.length; i < len; i++){
8840 p.fields.add(new Roo.data.Field(o[i]));
8842 f.getField = function(name){
8843 return p.fields.get(name);
8848 Roo.data.Record.AUTO_ID = 1000;
8849 Roo.data.Record.EDIT = 'edit';
8850 Roo.data.Record.REJECT = 'reject';
8851 Roo.data.Record.COMMIT = 'commit';
8853 Roo.data.Record.prototype = {
8855 * Readonly flag - true if this record has been modified.
8864 join : function(store){
8869 * Set the named field to the specified value.
8870 * @param {String} name The name of the field to set.
8871 * @param {Object} value The value to set the field to.
8873 set : function(name, value){
8874 if(this.data[name] == value){
8881 if(typeof this.modified[name] == 'undefined'){
8882 this.modified[name] = this.data[name];
8884 this.data[name] = value;
8885 if(!this.editing && this.store){
8886 this.store.afterEdit(this);
8891 * Get the value of the named field.
8892 * @param {String} name The name of the field to get the value of.
8893 * @return {Object} The value of the field.
8895 get : function(name){
8896 return this.data[name];
8900 beginEdit : function(){
8901 this.editing = true;
8906 cancelEdit : function(){
8907 this.editing = false;
8908 delete this.modified;
8912 endEdit : function(){
8913 this.editing = false;
8914 if(this.dirty && this.store){
8915 this.store.afterEdit(this);
8920 * Usually called by the {@link Roo.data.Store} which owns the Record.
8921 * Rejects all changes made to the Record since either creation, or the last commit operation.
8922 * Modified fields are reverted to their original values.
8924 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8925 * of reject operations.
8927 reject : function(){
8928 var m = this.modified;
8930 if(typeof m[n] != "function"){
8931 this.data[n] = m[n];
8935 delete this.modified;
8936 this.editing = false;
8938 this.store.afterReject(this);
8943 * Usually called by the {@link Roo.data.Store} which owns the Record.
8944 * Commits all changes made to the Record since either creation, or the last commit operation.
8946 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8947 * of commit operations.
8949 commit : function(){
8951 delete this.modified;
8952 this.editing = false;
8954 this.store.afterCommit(this);
8959 hasError : function(){
8960 return this.error != null;
8964 clearError : function(){
8969 * Creates a copy of this record.
8970 * @param {String} id (optional) A new record id if you don't want to use this record's id
8973 copy : function(newId) {
8974 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8978 * Ext JS Library 1.1.1
8979 * Copyright(c) 2006-2007, Ext JS, LLC.
8981 * Originally Released Under LGPL - original licence link has changed is not relivant.
8984 * <script type="text/javascript">
8990 * @class Roo.data.Store
8991 * @extends Roo.util.Observable
8992 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8993 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8995 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8996 * has no knowledge of the format of the data returned by the Proxy.<br>
8998 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8999 * instances from the data object. These records are cached and made available through accessor functions.
9001 * Creates a new Store.
9002 * @param {Object} config A config object containing the objects needed for the Store to access data,
9003 * and read the data into Records.
9005 Roo.data.Store = function(config){
9006 this.data = new Roo.util.MixedCollection(false);
9007 this.data.getKey = function(o){
9010 this.baseParams = {};
9017 "multisort" : "_multisort"
9020 if(config && config.data){
9021 this.inlineData = config.data;
9025 Roo.apply(this, config);
9027 if(this.reader){ // reader passed
9028 this.reader = Roo.factory(this.reader, Roo.data);
9029 this.reader.xmodule = this.xmodule || false;
9030 if(!this.recordType){
9031 this.recordType = this.reader.recordType;
9033 if(this.reader.onMetaChange){
9034 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9038 if(this.recordType){
9039 this.fields = this.recordType.prototype.fields;
9045 * @event datachanged
9046 * Fires when the data cache has changed, and a widget which is using this Store
9047 * as a Record cache should refresh its view.
9048 * @param {Store} this
9053 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9054 * @param {Store} this
9055 * @param {Object} meta The JSON metadata
9060 * Fires when Records have been added to the Store
9061 * @param {Store} this
9062 * @param {Roo.data.Record[]} records The array of Records added
9063 * @param {Number} index The index at which the record(s) were added
9068 * Fires when a Record has been removed from the Store
9069 * @param {Store} this
9070 * @param {Roo.data.Record} record The Record that was removed
9071 * @param {Number} index The index at which the record was removed
9076 * Fires when a Record has been updated
9077 * @param {Store} this
9078 * @param {Roo.data.Record} record The Record that was updated
9079 * @param {String} operation The update operation being performed. Value may be one of:
9081 Roo.data.Record.EDIT
9082 Roo.data.Record.REJECT
9083 Roo.data.Record.COMMIT
9089 * Fires when the data cache has been cleared.
9090 * @param {Store} this
9095 * Fires before a request is made for a new data object. If the beforeload handler returns false
9096 * the load action will be canceled.
9097 * @param {Store} this
9098 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9102 * @event beforeloadadd
9103 * Fires after a new set of Records has been loaded.
9104 * @param {Store} this
9105 * @param {Roo.data.Record[]} records The Records that were loaded
9106 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9108 beforeloadadd : true,
9111 * Fires after a new set of Records has been loaded, before they are added to the store.
9112 * @param {Store} this
9113 * @param {Roo.data.Record[]} records The Records that were loaded
9114 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9115 * @params {Object} return from reader
9119 * @event loadexception
9120 * Fires if an exception occurs in the Proxy during loading.
9121 * Called with the signature of the Proxy's "loadexception" event.
9122 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9125 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9126 * @param {Object} load options
9127 * @param {Object} jsonData from your request (normally this contains the Exception)
9129 loadexception : true
9133 this.proxy = Roo.factory(this.proxy, Roo.data);
9134 this.proxy.xmodule = this.xmodule || false;
9135 this.relayEvents(this.proxy, ["loadexception"]);
9137 this.sortToggle = {};
9138 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9140 Roo.data.Store.superclass.constructor.call(this);
9142 if(this.inlineData){
9143 this.loadData(this.inlineData);
9144 delete this.inlineData;
9148 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9150 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9151 * without a remote query - used by combo/forms at present.
9155 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9158 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9161 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9162 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9165 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9166 * on any HTTP request
9169 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9172 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9176 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9177 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9182 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9183 * loaded or when a record is removed. (defaults to false).
9185 pruneModifiedRecords : false,
9191 * Add Records to the Store and fires the add event.
9192 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9194 add : function(records){
9195 records = [].concat(records);
9196 for(var i = 0, len = records.length; i < len; i++){
9197 records[i].join(this);
9199 var index = this.data.length;
9200 this.data.addAll(records);
9201 this.fireEvent("add", this, records, index);
9205 * Remove a Record from the Store and fires the remove event.
9206 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9208 remove : function(record){
9209 var index = this.data.indexOf(record);
9210 this.data.removeAt(index);
9211 if(this.pruneModifiedRecords){
9212 this.modified.remove(record);
9214 this.fireEvent("remove", this, record, index);
9218 * Remove all Records from the Store and fires the clear event.
9220 removeAll : function(){
9222 if(this.pruneModifiedRecords){
9225 this.fireEvent("clear", this);
9229 * Inserts Records to the Store at the given index and fires the add event.
9230 * @param {Number} index The start index at which to insert the passed Records.
9231 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9233 insert : function(index, records){
9234 records = [].concat(records);
9235 for(var i = 0, len = records.length; i < len; i++){
9236 this.data.insert(index, records[i]);
9237 records[i].join(this);
9239 this.fireEvent("add", this, records, index);
9243 * Get the index within the cache of the passed Record.
9244 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9245 * @return {Number} The index of the passed Record. Returns -1 if not found.
9247 indexOf : function(record){
9248 return this.data.indexOf(record);
9252 * Get the index within the cache of the Record with the passed id.
9253 * @param {String} id The id of the Record to find.
9254 * @return {Number} The index of the Record. Returns -1 if not found.
9256 indexOfId : function(id){
9257 return this.data.indexOfKey(id);
9261 * Get the Record with the specified id.
9262 * @param {String} id The id of the Record to find.
9263 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9265 getById : function(id){
9266 return this.data.key(id);
9270 * Get the Record at the specified index.
9271 * @param {Number} index The index of the Record to find.
9272 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9274 getAt : function(index){
9275 return this.data.itemAt(index);
9279 * Returns a range of Records between specified indices.
9280 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9281 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9282 * @return {Roo.data.Record[]} An array of Records
9284 getRange : function(start, end){
9285 return this.data.getRange(start, end);
9289 storeOptions : function(o){
9290 o = Roo.apply({}, o);
9293 this.lastOptions = o;
9297 * Loads the Record cache from the configured Proxy using the configured Reader.
9299 * If using remote paging, then the first load call must specify the <em>start</em>
9300 * and <em>limit</em> properties in the options.params property to establish the initial
9301 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9303 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9304 * and this call will return before the new data has been loaded. Perform any post-processing
9305 * in a callback function, or in a "load" event handler.</strong>
9307 * @param {Object} options An object containing properties which control loading options:<ul>
9308 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9309 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9310 * passed the following arguments:<ul>
9311 * <li>r : Roo.data.Record[]</li>
9312 * <li>options: Options object from the load call</li>
9313 * <li>success: Boolean success indicator</li></ul></li>
9314 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9315 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9318 load : function(options){
9319 options = options || {};
9320 if(this.fireEvent("beforeload", this, options) !== false){
9321 this.storeOptions(options);
9322 var p = Roo.apply(options.params || {}, this.baseParams);
9323 // if meta was not loaded from remote source.. try requesting it.
9324 if (!this.reader.metaFromRemote) {
9327 if(this.sortInfo && this.remoteSort){
9328 var pn = this.paramNames;
9329 p[pn["sort"]] = this.sortInfo.field;
9330 p[pn["dir"]] = this.sortInfo.direction;
9332 if (this.multiSort) {
9333 var pn = this.paramNames;
9334 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9337 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9342 * Reloads the Record cache from the configured Proxy using the configured Reader and
9343 * the options from the last load operation performed.
9344 * @param {Object} options (optional) An object containing properties which may override the options
9345 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9346 * the most recently used options are reused).
9348 reload : function(options){
9349 this.load(Roo.applyIf(options||{}, this.lastOptions));
9353 // Called as a callback by the Reader during a load operation.
9354 loadRecords : function(o, options, success){
9355 if(!o || success === false){
9356 if(success !== false){
9357 this.fireEvent("load", this, [], options, o);
9359 if(options.callback){
9360 options.callback.call(options.scope || this, [], options, false);
9364 // if data returned failure - throw an exception.
9365 if (o.success === false) {
9366 // show a message if no listener is registered.
9367 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9368 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9370 // loadmask wil be hooked into this..
9371 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9374 var r = o.records, t = o.totalRecords || r.length;
9376 this.fireEvent("beforeloadadd", this, r, options, o);
9378 if(!options || options.add !== true){
9379 if(this.pruneModifiedRecords){
9382 for(var i = 0, len = r.length; i < len; i++){
9386 this.data = this.snapshot;
9387 delete this.snapshot;
9390 this.data.addAll(r);
9391 this.totalLength = t;
9393 this.fireEvent("datachanged", this);
9395 this.totalLength = Math.max(t, this.data.length+r.length);
9398 this.fireEvent("load", this, r, options, o);
9399 if(options.callback){
9400 options.callback.call(options.scope || this, r, options, true);
9406 * Loads data from a passed data block. A Reader which understands the format of the data
9407 * must have been configured in the constructor.
9408 * @param {Object} data The data block from which to read the Records. The format of the data expected
9409 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9410 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9412 loadData : function(o, append){
9413 var r = this.reader.readRecords(o);
9414 this.loadRecords(r, {add: append}, true);
9418 * Gets the number of cached records.
9420 * <em>If using paging, this may not be the total size of the dataset. If the data object
9421 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9422 * the data set size</em>
9424 getCount : function(){
9425 return this.data.length || 0;
9429 * Gets the total number of records in the dataset as returned by the server.
9431 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9432 * the dataset size</em>
9434 getTotalCount : function(){
9435 return this.totalLength || 0;
9439 * Returns the sort state of the Store as an object with two properties:
9441 field {String} The name of the field by which the Records are sorted
9442 direction {String} The sort order, "ASC" or "DESC"
9445 getSortState : function(){
9446 return this.sortInfo;
9450 applySort : function(){
9451 if(this.sortInfo && !this.remoteSort){
9452 var s = this.sortInfo, f = s.field;
9453 var st = this.fields.get(f).sortType;
9454 var fn = function(r1, r2){
9455 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9456 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9458 this.data.sort(s.direction, fn);
9459 if(this.snapshot && this.snapshot != this.data){
9460 this.snapshot.sort(s.direction, fn);
9466 * Sets the default sort column and order to be used by the next load operation.
9467 * @param {String} fieldName The name of the field to sort by.
9468 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9470 setDefaultSort : function(field, dir){
9471 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9476 * If remote sorting is used, the sort is performed on the server, and the cache is
9477 * reloaded. If local sorting is used, the cache is sorted internally.
9478 * @param {String} fieldName The name of the field to sort by.
9479 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9481 sort : function(fieldName, dir){
9482 var f = this.fields.get(fieldName);
9484 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9486 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9487 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9492 this.sortToggle[f.name] = dir;
9493 this.sortInfo = {field: f.name, direction: dir};
9494 if(!this.remoteSort){
9496 this.fireEvent("datachanged", this);
9498 this.load(this.lastOptions);
9503 * Calls the specified function for each of the Records in the cache.
9504 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9505 * Returning <em>false</em> aborts and exits the iteration.
9506 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9508 each : function(fn, scope){
9509 this.data.each(fn, scope);
9513 * Gets all records modified since the last commit. Modified records are persisted across load operations
9514 * (e.g., during paging).
9515 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9517 getModifiedRecords : function(){
9518 return this.modified;
9522 createFilterFn : function(property, value, anyMatch){
9523 if(!value.exec){ // not a regex
9524 value = String(value);
9525 if(value.length == 0){
9528 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9531 return value.test(r.data[property]);
9536 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9537 * @param {String} property A field on your records
9538 * @param {Number} start The record index to start at (defaults to 0)
9539 * @param {Number} end The last record index to include (defaults to length - 1)
9540 * @return {Number} The sum
9542 sum : function(property, start, end){
9543 var rs = this.data.items, v = 0;
9545 end = (end || end === 0) ? end : rs.length-1;
9547 for(var i = start; i <= end; i++){
9548 v += (rs[i].data[property] || 0);
9554 * Filter the records by a specified property.
9555 * @param {String} field A field on your records
9556 * @param {String/RegExp} value Either a string that the field
9557 * should start with or a RegExp to test against the field
9558 * @param {Boolean} anyMatch True to match any part not just the beginning
9560 filter : function(property, value, anyMatch){
9561 var fn = this.createFilterFn(property, value, anyMatch);
9562 return fn ? this.filterBy(fn) : this.clearFilter();
9566 * Filter by a function. The specified function will be called with each
9567 * record in this data source. If the function returns true the record is included,
9568 * otherwise it is filtered.
9569 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9570 * @param {Object} scope (optional) The scope of the function (defaults to this)
9572 filterBy : function(fn, scope){
9573 this.snapshot = this.snapshot || this.data;
9574 this.data = this.queryBy(fn, scope||this);
9575 this.fireEvent("datachanged", this);
9579 * Query the records by a specified property.
9580 * @param {String} field A field on your records
9581 * @param {String/RegExp} value Either a string that the field
9582 * should start with or a RegExp to test against the field
9583 * @param {Boolean} anyMatch True to match any part not just the beginning
9584 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9586 query : function(property, value, anyMatch){
9587 var fn = this.createFilterFn(property, value, anyMatch);
9588 return fn ? this.queryBy(fn) : this.data.clone();
9592 * Query by a function. The specified function will be called with each
9593 * record in this data source. If the function returns true the record is included
9595 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9596 * @param {Object} scope (optional) The scope of the function (defaults to this)
9597 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9599 queryBy : function(fn, scope){
9600 var data = this.snapshot || this.data;
9601 return data.filterBy(fn, scope||this);
9605 * Collects unique values for a particular dataIndex from this store.
9606 * @param {String} dataIndex The property to collect
9607 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9608 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9609 * @return {Array} An array of the unique values
9611 collect : function(dataIndex, allowNull, bypassFilter){
9612 var d = (bypassFilter === true && this.snapshot) ?
9613 this.snapshot.items : this.data.items;
9614 var v, sv, r = [], l = {};
9615 for(var i = 0, len = d.length; i < len; i++){
9616 v = d[i].data[dataIndex];
9618 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9627 * Revert to a view of the Record cache with no filtering applied.
9628 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9630 clearFilter : function(suppressEvent){
9631 if(this.snapshot && this.snapshot != this.data){
9632 this.data = this.snapshot;
9633 delete this.snapshot;
9634 if(suppressEvent !== true){
9635 this.fireEvent("datachanged", this);
9641 afterEdit : function(record){
9642 if(this.modified.indexOf(record) == -1){
9643 this.modified.push(record);
9645 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9649 afterReject : function(record){
9650 this.modified.remove(record);
9651 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9655 afterCommit : function(record){
9656 this.modified.remove(record);
9657 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9661 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9662 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9664 commitChanges : function(){
9665 var m = this.modified.slice(0);
9667 for(var i = 0, len = m.length; i < len; i++){
9673 * Cancel outstanding changes on all changed records.
9675 rejectChanges : function(){
9676 var m = this.modified.slice(0);
9678 for(var i = 0, len = m.length; i < len; i++){
9683 onMetaChange : function(meta, rtype, o){
9684 this.recordType = rtype;
9685 this.fields = rtype.prototype.fields;
9686 delete this.snapshot;
9687 this.sortInfo = meta.sortInfo || this.sortInfo;
9689 this.fireEvent('metachange', this, this.reader.meta);
9692 moveIndex : function(data, type)
9694 var index = this.indexOf(data);
9696 var newIndex = index + type;
9700 this.insert(newIndex, data);
9705 * Ext JS Library 1.1.1
9706 * Copyright(c) 2006-2007, Ext JS, LLC.
9708 * Originally Released Under LGPL - original licence link has changed is not relivant.
9711 * <script type="text/javascript">
9715 * @class Roo.data.SimpleStore
9716 * @extends Roo.data.Store
9717 * Small helper class to make creating Stores from Array data easier.
9718 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9719 * @cfg {Array} fields An array of field definition objects, or field name strings.
9720 * @cfg {Array} data The multi-dimensional array of data
9722 * @param {Object} config
9724 Roo.data.SimpleStore = function(config){
9725 Roo.data.SimpleStore.superclass.constructor.call(this, {
9727 reader: new Roo.data.ArrayReader({
9730 Roo.data.Record.create(config.fields)
9732 proxy : new Roo.data.MemoryProxy(config.data)
9736 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9738 * Ext JS Library 1.1.1
9739 * Copyright(c) 2006-2007, Ext JS, LLC.
9741 * Originally Released Under LGPL - original licence link has changed is not relivant.
9744 * <script type="text/javascript">
9749 * @extends Roo.data.Store
9750 * @class Roo.data.JsonStore
9751 * Small helper class to make creating Stores for JSON data easier. <br/>
9753 var store = new Roo.data.JsonStore({
9754 url: 'get-images.php',
9756 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9759 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9760 * JsonReader and HttpProxy (unless inline data is provided).</b>
9761 * @cfg {Array} fields An array of field definition objects, or field name strings.
9763 * @param {Object} config
9765 Roo.data.JsonStore = function(c){
9766 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9767 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9768 reader: new Roo.data.JsonReader(c, c.fields)
9771 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9773 * Ext JS Library 1.1.1
9774 * Copyright(c) 2006-2007, Ext JS, LLC.
9776 * Originally Released Under LGPL - original licence link has changed is not relivant.
9779 * <script type="text/javascript">
9783 Roo.data.Field = function(config){
9784 if(typeof config == "string"){
9785 config = {name: config};
9787 Roo.apply(this, config);
9793 var st = Roo.data.SortTypes;
9794 // named sortTypes are supported, here we look them up
9795 if(typeof this.sortType == "string"){
9796 this.sortType = st[this.sortType];
9799 // set default sortType for strings and dates
9803 this.sortType = st.asUCString;
9806 this.sortType = st.asDate;
9809 this.sortType = st.none;
9814 var stripRe = /[\$,%]/g;
9816 // prebuilt conversion function for this field, instead of
9817 // switching every time we're reading a value
9819 var cv, dateFormat = this.dateFormat;
9824 cv = function(v){ return v; };
9827 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9831 return v !== undefined && v !== null && v !== '' ?
9832 parseInt(String(v).replace(stripRe, ""), 10) : '';
9837 return v !== undefined && v !== null && v !== '' ?
9838 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9843 cv = function(v){ return v === true || v === "true" || v == 1; };
9850 if(v instanceof Date){
9854 if(dateFormat == "timestamp"){
9855 return new Date(v*1000);
9857 return Date.parseDate(v, dateFormat);
9859 var parsed = Date.parse(v);
9860 return parsed ? new Date(parsed) : null;
9869 Roo.data.Field.prototype = {
9877 * Ext JS Library 1.1.1
9878 * Copyright(c) 2006-2007, Ext JS, LLC.
9880 * Originally Released Under LGPL - original licence link has changed is not relivant.
9883 * <script type="text/javascript">
9886 // Base class for reading structured data from a data source. This class is intended to be
9887 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9890 * @class Roo.data.DataReader
9891 * Base class for reading structured data from a data source. This class is intended to be
9892 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9895 Roo.data.DataReader = function(meta, recordType){
9899 this.recordType = recordType instanceof Array ?
9900 Roo.data.Record.create(recordType) : recordType;
9903 Roo.data.DataReader.prototype = {
9905 * Create an empty record
9906 * @param {Object} data (optional) - overlay some values
9907 * @return {Roo.data.Record} record created.
9909 newRow : function(d) {
9911 this.recordType.prototype.fields.each(function(c) {
9913 case 'int' : da[c.name] = 0; break;
9914 case 'date' : da[c.name] = new Date(); break;
9915 case 'float' : da[c.name] = 0.0; break;
9916 case 'boolean' : da[c.name] = false; break;
9917 default : da[c.name] = ""; break;
9921 return new this.recordType(Roo.apply(da, d));
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">
9936 * @class Roo.data.DataProxy
9937 * @extends Roo.data.Observable
9938 * This class is an abstract base class for implementations which provide retrieval of
9939 * unformatted data objects.<br>
9941 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9942 * (of the appropriate type which knows how to parse the data object) to provide a block of
9943 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9945 * Custom implementations must implement the load method as described in
9946 * {@link Roo.data.HttpProxy#load}.
9948 Roo.data.DataProxy = function(){
9952 * Fires before a network request is made to retrieve a data object.
9953 * @param {Object} This DataProxy object.
9954 * @param {Object} params The params parameter to the load function.
9959 * Fires before the load method's callback is called.
9960 * @param {Object} This DataProxy object.
9961 * @param {Object} o The data object.
9962 * @param {Object} arg The callback argument object passed to the load function.
9966 * @event loadexception
9967 * Fires if an Exception occurs during data retrieval.
9968 * @param {Object} This DataProxy object.
9969 * @param {Object} o The data object.
9970 * @param {Object} arg The callback argument object passed to the load function.
9971 * @param {Object} e The Exception.
9973 loadexception : true
9975 Roo.data.DataProxy.superclass.constructor.call(this);
9978 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9981 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9985 * Ext JS Library 1.1.1
9986 * Copyright(c) 2006-2007, Ext JS, LLC.
9988 * Originally Released Under LGPL - original licence link has changed is not relivant.
9991 * <script type="text/javascript">
9994 * @class Roo.data.MemoryProxy
9995 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9996 * to the Reader when its load method is called.
9998 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10000 Roo.data.MemoryProxy = function(data){
10004 Roo.data.MemoryProxy.superclass.constructor.call(this);
10008 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10010 * Load data from the requested source (in this case an in-memory
10011 * data object passed to the constructor), read the data object into
10012 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10013 * process that block using the passed callback.
10014 * @param {Object} params This parameter is not used by the MemoryProxy class.
10015 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10016 * object into a block of Roo.data.Records.
10017 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10018 * The function must be passed <ul>
10019 * <li>The Record block object</li>
10020 * <li>The "arg" argument from the load function</li>
10021 * <li>A boolean success indicator</li>
10023 * @param {Object} scope The scope in which to call the callback
10024 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10026 load : function(params, reader, callback, scope, arg){
10027 params = params || {};
10030 result = reader.readRecords(this.data);
10032 this.fireEvent("loadexception", this, arg, null, e);
10033 callback.call(scope, null, arg, false);
10036 callback.call(scope, result, arg, true);
10040 update : function(params, records){
10045 * Ext JS Library 1.1.1
10046 * Copyright(c) 2006-2007, Ext JS, LLC.
10048 * Originally Released Under LGPL - original licence link has changed is not relivant.
10051 * <script type="text/javascript">
10054 * @class Roo.data.HttpProxy
10055 * @extends Roo.data.DataProxy
10056 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10057 * configured to reference a certain URL.<br><br>
10059 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10060 * from which the running page was served.<br><br>
10062 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10064 * Be aware that to enable the browser to parse an XML document, the server must set
10065 * the Content-Type header in the HTTP response to "text/xml".
10067 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10068 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10069 * will be used to make the request.
10071 Roo.data.HttpProxy = function(conn){
10072 Roo.data.HttpProxy.superclass.constructor.call(this);
10073 // is conn a conn config or a real conn?
10075 this.useAjax = !conn || !conn.events;
10079 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10080 // thse are take from connection...
10083 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10086 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10087 * extra parameters to each request made by this object. (defaults to undefined)
10090 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10091 * to each request made by this object. (defaults to undefined)
10094 * @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)
10097 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10100 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10106 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10110 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10111 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10112 * a finer-grained basis than the DataProxy events.
10114 getConnection : function(){
10115 return this.useAjax ? Roo.Ajax : this.conn;
10119 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10120 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10121 * process that block using the passed callback.
10122 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10123 * for the request to the remote server.
10124 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10125 * object into a block of Roo.data.Records.
10126 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10127 * The function must be passed <ul>
10128 * <li>The Record block object</li>
10129 * <li>The "arg" argument from the load function</li>
10130 * <li>A boolean success indicator</li>
10132 * @param {Object} scope The scope in which to call the callback
10133 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10135 load : function(params, reader, callback, scope, arg){
10136 if(this.fireEvent("beforeload", this, params) !== false){
10138 params : params || {},
10140 callback : callback,
10145 callback : this.loadResponse,
10149 Roo.applyIf(o, this.conn);
10150 if(this.activeRequest){
10151 Roo.Ajax.abort(this.activeRequest);
10153 this.activeRequest = Roo.Ajax.request(o);
10155 this.conn.request(o);
10158 callback.call(scope||this, null, arg, false);
10163 loadResponse : function(o, success, response){
10164 delete this.activeRequest;
10166 this.fireEvent("loadexception", this, o, response);
10167 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10172 result = o.reader.read(response);
10174 this.fireEvent("loadexception", this, o, response, e);
10175 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10179 this.fireEvent("load", this, o, o.request.arg);
10180 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10184 update : function(dataSet){
10189 updateResponse : function(dataSet){
10194 * Ext JS Library 1.1.1
10195 * Copyright(c) 2006-2007, Ext JS, LLC.
10197 * Originally Released Under LGPL - original licence link has changed is not relivant.
10200 * <script type="text/javascript">
10204 * @class Roo.data.ScriptTagProxy
10205 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10206 * other than the originating domain of the running page.<br><br>
10208 * <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
10209 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10211 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10212 * source code that is used as the source inside a <script> tag.<br><br>
10214 * In order for the browser to process the returned data, the server must wrap the data object
10215 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10216 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10217 * depending on whether the callback name was passed:
10220 boolean scriptTag = false;
10221 String cb = request.getParameter("callback");
10224 response.setContentType("text/javascript");
10226 response.setContentType("application/x-json");
10228 Writer out = response.getWriter();
10230 out.write(cb + "(");
10232 out.print(dataBlock.toJsonString());
10239 * @param {Object} config A configuration object.
10241 Roo.data.ScriptTagProxy = function(config){
10242 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10243 Roo.apply(this, config);
10244 this.head = document.getElementsByTagName("head")[0];
10247 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10249 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10251 * @cfg {String} url The URL from which to request the data object.
10254 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10258 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10259 * the server the name of the callback function set up by the load call to process the returned data object.
10260 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10261 * javascript output which calls this named function passing the data object as its only parameter.
10263 callbackParam : "callback",
10265 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10266 * name to the request.
10271 * Load data from the configured URL, read the data object into
10272 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10273 * process that block using the passed callback.
10274 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10275 * for the request to the remote server.
10276 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10277 * object into a block of Roo.data.Records.
10278 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10279 * The function must be passed <ul>
10280 * <li>The Record block object</li>
10281 * <li>The "arg" argument from the load function</li>
10282 * <li>A boolean success indicator</li>
10284 * @param {Object} scope The scope in which to call the callback
10285 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10287 load : function(params, reader, callback, scope, arg){
10288 if(this.fireEvent("beforeload", this, params) !== false){
10290 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10292 var url = this.url;
10293 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10295 url += "&_dc=" + (new Date().getTime());
10297 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10300 cb : "stcCallback"+transId,
10301 scriptId : "stcScript"+transId,
10305 callback : callback,
10311 window[trans.cb] = function(o){
10312 conn.handleResponse(o, trans);
10315 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10317 if(this.autoAbort !== false){
10321 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10323 var script = document.createElement("script");
10324 script.setAttribute("src", url);
10325 script.setAttribute("type", "text/javascript");
10326 script.setAttribute("id", trans.scriptId);
10327 this.head.appendChild(script);
10329 this.trans = trans;
10331 callback.call(scope||this, null, arg, false);
10336 isLoading : function(){
10337 return this.trans ? true : false;
10341 * Abort the current server request.
10343 abort : function(){
10344 if(this.isLoading()){
10345 this.destroyTrans(this.trans);
10350 destroyTrans : function(trans, isLoaded){
10351 this.head.removeChild(document.getElementById(trans.scriptId));
10352 clearTimeout(trans.timeoutId);
10354 window[trans.cb] = undefined;
10356 delete window[trans.cb];
10359 // if hasn't been loaded, wait for load to remove it to prevent script error
10360 window[trans.cb] = function(){
10361 window[trans.cb] = undefined;
10363 delete window[trans.cb];
10370 handleResponse : function(o, trans){
10371 this.trans = false;
10372 this.destroyTrans(trans, true);
10375 result = trans.reader.readRecords(o);
10377 this.fireEvent("loadexception", this, o, trans.arg, e);
10378 trans.callback.call(trans.scope||window, null, trans.arg, false);
10381 this.fireEvent("load", this, o, trans.arg);
10382 trans.callback.call(trans.scope||window, result, trans.arg, true);
10386 handleFailure : function(trans){
10387 this.trans = false;
10388 this.destroyTrans(trans, false);
10389 this.fireEvent("loadexception", this, null, trans.arg);
10390 trans.callback.call(trans.scope||window, null, trans.arg, false);
10394 * Ext JS Library 1.1.1
10395 * Copyright(c) 2006-2007, Ext JS, LLC.
10397 * Originally Released Under LGPL - original licence link has changed is not relivant.
10400 * <script type="text/javascript">
10404 * @class Roo.data.JsonReader
10405 * @extends Roo.data.DataReader
10406 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10407 * based on mappings in a provided Roo.data.Record constructor.
10409 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10410 * in the reply previously.
10415 var RecordDef = Roo.data.Record.create([
10416 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10417 {name: 'occupation'} // This field will use "occupation" as the mapping.
10419 var myReader = new Roo.data.JsonReader({
10420 totalProperty: "results", // The property which contains the total dataset size (optional)
10421 root: "rows", // The property which contains an Array of row objects
10422 id: "id" // The property within each row object that provides an ID for the record (optional)
10426 * This would consume a JSON file like this:
10428 { 'results': 2, 'rows': [
10429 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10430 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10433 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10434 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10435 * paged from the remote server.
10436 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10437 * @cfg {String} root name of the property which contains the Array of row objects.
10438 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10440 * Create a new JsonReader
10441 * @param {Object} meta Metadata configuration options
10442 * @param {Object} recordType Either an Array of field definition objects,
10443 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10445 Roo.data.JsonReader = function(meta, recordType){
10448 // set some defaults:
10449 Roo.applyIf(meta, {
10450 totalProperty: 'total',
10451 successProperty : 'success',
10456 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10458 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10461 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10462 * Used by Store query builder to append _requestMeta to params.
10465 metaFromRemote : false,
10467 * This method is only used by a DataProxy which has retrieved data from a remote server.
10468 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10469 * @return {Object} data A data block which is used by an Roo.data.Store object as
10470 * a cache of Roo.data.Records.
10472 read : function(response){
10473 var json = response.responseText;
10475 var o = /* eval:var:o */ eval("("+json+")");
10477 throw {message: "JsonReader.read: Json object not found"};
10483 this.metaFromRemote = true;
10484 this.meta = o.metaData;
10485 this.recordType = Roo.data.Record.create(o.metaData.fields);
10486 this.onMetaChange(this.meta, this.recordType, o);
10488 return this.readRecords(o);
10491 // private function a store will implement
10492 onMetaChange : function(meta, recordType, o){
10499 simpleAccess: function(obj, subsc) {
10506 getJsonAccessor: function(){
10508 return function(expr) {
10510 return(re.test(expr))
10511 ? new Function("obj", "return obj." + expr)
10516 return Roo.emptyFn;
10521 * Create a data block containing Roo.data.Records from an XML document.
10522 * @param {Object} o An object which contains an Array of row objects in the property specified
10523 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10524 * which contains the total size of the dataset.
10525 * @return {Object} data A data block which is used by an Roo.data.Store object as
10526 * a cache of Roo.data.Records.
10528 readRecords : function(o){
10530 * After any data loads, the raw JSON data is available for further custom processing.
10534 var s = this.meta, Record = this.recordType,
10535 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10537 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10539 if(s.totalProperty) {
10540 this.getTotal = this.getJsonAccessor(s.totalProperty);
10542 if(s.successProperty) {
10543 this.getSuccess = this.getJsonAccessor(s.successProperty);
10545 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10547 var g = this.getJsonAccessor(s.id);
10548 this.getId = function(rec) {
10550 return (r === undefined || r === "") ? null : r;
10553 this.getId = function(){return null;};
10556 for(var jj = 0; jj < fl; jj++){
10558 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10559 this.ef[jj] = this.getJsonAccessor(map);
10563 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10564 if(s.totalProperty){
10565 var vt = parseInt(this.getTotal(o), 10);
10570 if(s.successProperty){
10571 var vs = this.getSuccess(o);
10572 if(vs === false || vs === 'false'){
10577 for(var i = 0; i < c; i++){
10580 var id = this.getId(n);
10581 for(var j = 0; j < fl; j++){
10583 var v = this.ef[j](n);
10585 Roo.log('missing convert for ' + f.name);
10589 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10591 var record = new Record(values, id);
10593 records[i] = record;
10599 totalRecords : totalRecords
10604 * Ext JS Library 1.1.1
10605 * Copyright(c) 2006-2007, Ext JS, LLC.
10607 * Originally Released Under LGPL - original licence link has changed is not relivant.
10610 * <script type="text/javascript">
10614 * @class Roo.data.ArrayReader
10615 * @extends Roo.data.DataReader
10616 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10617 * Each element of that Array represents a row of data fields. The
10618 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10619 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10623 var RecordDef = Roo.data.Record.create([
10624 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10625 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10627 var myReader = new Roo.data.ArrayReader({
10628 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10632 * This would consume an Array like this:
10634 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10636 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10638 * Create a new JsonReader
10639 * @param {Object} meta Metadata configuration options.
10640 * @param {Object} recordType Either an Array of field definition objects
10641 * as specified to {@link Roo.data.Record#create},
10642 * or an {@link Roo.data.Record} object
10643 * created using {@link Roo.data.Record#create}.
10645 Roo.data.ArrayReader = function(meta, recordType){
10646 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10649 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10651 * Create a data block containing Roo.data.Records from an XML document.
10652 * @param {Object} o An Array of row objects which represents the dataset.
10653 * @return {Object} data A data block which is used by an Roo.data.Store object as
10654 * a cache of Roo.data.Records.
10656 readRecords : function(o){
10657 var sid = this.meta ? this.meta.id : null;
10658 var recordType = this.recordType, fields = recordType.prototype.fields;
10661 for(var i = 0; i < root.length; i++){
10664 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10665 for(var j = 0, jlen = fields.length; j < jlen; j++){
10666 var f = fields.items[j];
10667 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10668 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10670 values[f.name] = v;
10672 var record = new recordType(values, id);
10674 records[records.length] = record;
10678 totalRecords : records.length
10687 * @class Roo.bootstrap.ComboBox
10688 * @extends Roo.bootstrap.TriggerField
10689 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10690 * @cfg {Boolean} append (true|false) default false
10691 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10692 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10693 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10694 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10695 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10697 * Create a new ComboBox.
10698 * @param {Object} config Configuration options
10700 Roo.bootstrap.ComboBox = function(config){
10701 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10705 * Fires when the dropdown list is expanded
10706 * @param {Roo.bootstrap.ComboBox} combo This combo box
10711 * Fires when the dropdown list is collapsed
10712 * @param {Roo.bootstrap.ComboBox} combo This combo box
10716 * @event beforeselect
10717 * Fires before a list item is selected. Return false to cancel the selection.
10718 * @param {Roo.bootstrap.ComboBox} combo This combo box
10719 * @param {Roo.data.Record} record The data record returned from the underlying store
10720 * @param {Number} index The index of the selected item in the dropdown list
10722 'beforeselect' : true,
10725 * Fires when a list item is selected
10726 * @param {Roo.bootstrap.ComboBox} combo This combo box
10727 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10728 * @param {Number} index The index of the selected item in the dropdown list
10732 * @event beforequery
10733 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10734 * The event object passed has these properties:
10735 * @param {Roo.bootstrap.ComboBox} combo This combo box
10736 * @param {String} query The query
10737 * @param {Boolean} forceAll true to force "all" query
10738 * @param {Boolean} cancel true to cancel the query
10739 * @param {Object} e The query event object
10741 'beforequery': true,
10744 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10745 * @param {Roo.bootstrap.ComboBox} combo This combo box
10750 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10751 * @param {Roo.bootstrap.ComboBox} combo This combo box
10752 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10757 * Fires when the remove value from the combobox array
10758 * @param {Roo.bootstrap.ComboBox} combo This combo box
10765 this.tickItems = [];
10767 this.selectedIndex = -1;
10768 if(this.mode == 'local'){
10769 if(config.queryDelay === undefined){
10770 this.queryDelay = 10;
10772 if(config.minChars === undefined){
10778 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10781 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10782 * rendering into an Roo.Editor, defaults to false)
10785 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10786 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10789 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10792 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10793 * the dropdown list (defaults to undefined, with no header element)
10797 * @cfg {String/Roo.Template} tpl The template to use to render the output
10801 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10803 listWidth: undefined,
10805 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10806 * mode = 'remote' or 'text' if mode = 'local')
10808 displayField: undefined,
10810 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10811 * mode = 'remote' or 'value' if mode = 'local').
10812 * Note: use of a valueField requires the user make a selection
10813 * in order for a value to be mapped.
10815 valueField: undefined,
10819 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10820 * field's data value (defaults to the underlying DOM element's name)
10822 hiddenName: undefined,
10824 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10828 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10830 selectedClass: 'active',
10833 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10837 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10838 * anchor positions (defaults to 'tl-bl')
10840 listAlign: 'tl-bl?',
10842 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10846 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10847 * query specified by the allQuery config option (defaults to 'query')
10849 triggerAction: 'query',
10851 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10852 * (defaults to 4, does not apply if editable = false)
10856 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10857 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10861 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10862 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10866 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10867 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10871 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10872 * when editable = true (defaults to false)
10874 selectOnFocus:false,
10876 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10878 queryParam: 'query',
10880 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10881 * when mode = 'remote' (defaults to 'Loading...')
10883 loadingText: 'Loading...',
10885 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10889 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10893 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10894 * traditional select (defaults to true)
10898 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10902 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10906 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10907 * listWidth has a higher value)
10911 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10912 * allow the user to set arbitrary text into the field (defaults to false)
10914 forceSelection:false,
10916 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10917 * if typeAhead = true (defaults to 250)
10919 typeAheadDelay : 250,
10921 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10922 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10924 valueNotFoundText : undefined,
10926 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10928 blockFocus : false,
10931 * @cfg {Boolean} disableClear Disable showing of clear button.
10933 disableClear : false,
10935 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10937 alwaysQuery : false,
10940 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10945 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10947 invalidClass : "has-warning",
10950 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10952 validClass : "has-success",
10964 btnPosition : 'right',
10965 triggerList : true,
10966 showToggleBtn : true,
10967 // element that contains real text value.. (when hidden is used..)
10969 getAutoCreate : function()
10976 if(!this.tickable){
10977 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10982 * ComboBox with tickable selections
10985 var align = this.labelAlign || this.parentLabelAlign();
10988 cls : 'form-group roo-combobox-tickable' //input-group
10993 cls : 'tickable-buttons',
10998 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11005 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11012 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11019 buttons.cn.unshift({
11021 cls: 'select2-search-field-input'
11027 Roo.each(buttons.cn, function(c){
11029 c.cls += ' btn-' + _this.size;
11032 if (_this.disabled) {
11043 cls: 'form-hidden-field'
11047 cls: 'select2-choices',
11051 cls: 'select2-search-field',
11063 cls: 'select2-container input-group select2-container-multi',
11068 // cls: 'typeahead typeahead-long dropdown-menu',
11069 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11074 if(this.hasFeedback && !this.allowBlank){
11078 cls: 'glyphicon form-control-feedback'
11081 combobox.cn.push(feedback);
11084 if (align ==='left' && this.fieldLabel.length) {
11086 Roo.log("left and has label");
11092 cls : 'control-label col-sm-' + this.labelWidth,
11093 html : this.fieldLabel
11097 cls : "col-sm-" + (12 - this.labelWidth),
11104 } else if ( this.fieldLabel.length) {
11110 //cls : 'input-group-addon',
11111 html : this.fieldLabel
11121 Roo.log(" no label && no align");
11128 ['xs','sm','md','lg'].map(function(size){
11129 if (settings[size]) {
11130 cfg.cls += ' col-' + size + '-' + settings[size];
11139 initEvents: function()
11143 throw "can not find store for combo";
11145 this.store = Roo.factory(this.store, Roo.data);
11148 this.initTickableEvents();
11152 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11154 if(this.hiddenName){
11156 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11158 this.hiddenField.dom.value =
11159 this.hiddenValue !== undefined ? this.hiddenValue :
11160 this.value !== undefined ? this.value : '';
11162 // prevent input submission
11163 this.el.dom.removeAttribute('name');
11164 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11169 // this.el.dom.setAttribute('autocomplete', 'off');
11172 var cls = 'x-combo-list';
11174 //this.list = new Roo.Layer({
11175 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11181 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11182 _this.list.setWidth(lw);
11185 this.list.on('mouseover', this.onViewOver, this);
11186 this.list.on('mousemove', this.onViewMove, this);
11188 this.list.on('scroll', this.onViewScroll, this);
11191 this.list.swallowEvent('mousewheel');
11192 this.assetHeight = 0;
11195 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11196 this.assetHeight += this.header.getHeight();
11199 this.innerList = this.list.createChild({cls:cls+'-inner'});
11200 this.innerList.on('mouseover', this.onViewOver, this);
11201 this.innerList.on('mousemove', this.onViewMove, this);
11202 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11204 if(this.allowBlank && !this.pageSize && !this.disableClear){
11205 this.footer = this.list.createChild({cls:cls+'-ft'});
11206 this.pageTb = new Roo.Toolbar(this.footer);
11210 this.footer = this.list.createChild({cls:cls+'-ft'});
11211 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11212 {pageSize: this.pageSize});
11216 if (this.pageTb && this.allowBlank && !this.disableClear) {
11218 this.pageTb.add(new Roo.Toolbar.Fill(), {
11219 cls: 'x-btn-icon x-btn-clear',
11221 handler: function()
11224 _this.clearValue();
11225 _this.onSelect(false, -1);
11230 this.assetHeight += this.footer.getHeight();
11235 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11238 this.view = new Roo.View(this.list, this.tpl, {
11239 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11241 //this.view.wrapEl.setDisplayed(false);
11242 this.view.on('click', this.onViewClick, this);
11246 this.store.on('beforeload', this.onBeforeLoad, this);
11247 this.store.on('load', this.onLoad, this);
11248 this.store.on('loadexception', this.onLoadException, this);
11250 if(this.resizable){
11251 this.resizer = new Roo.Resizable(this.list, {
11252 pinned:true, handles:'se'
11254 this.resizer.on('resize', function(r, w, h){
11255 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11256 this.listWidth = w;
11257 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11258 this.restrictHeight();
11260 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11263 if(!this.editable){
11264 this.editable = true;
11265 this.setEditable(false);
11270 if (typeof(this.events.add.listeners) != 'undefined') {
11272 this.addicon = this.wrap.createChild(
11273 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11275 this.addicon.on('click', function(e) {
11276 this.fireEvent('add', this);
11279 if (typeof(this.events.edit.listeners) != 'undefined') {
11281 this.editicon = this.wrap.createChild(
11282 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11283 if (this.addicon) {
11284 this.editicon.setStyle('margin-left', '40px');
11286 this.editicon.on('click', function(e) {
11288 // we fire even if inothing is selected..
11289 this.fireEvent('edit', this, this.lastData );
11295 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11296 "up" : function(e){
11297 this.inKeyMode = true;
11301 "down" : function(e){
11302 if(!this.isExpanded()){
11303 this.onTriggerClick();
11305 this.inKeyMode = true;
11310 "enter" : function(e){
11311 // this.onViewClick();
11315 if(this.fireEvent("specialkey", this, e)){
11316 this.onViewClick(false);
11322 "esc" : function(e){
11326 "tab" : function(e){
11329 if(this.fireEvent("specialkey", this, e)){
11330 this.onViewClick(false);
11338 doRelay : function(foo, bar, hname){
11339 if(hname == 'down' || this.scope.isExpanded()){
11340 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11349 this.queryDelay = Math.max(this.queryDelay || 10,
11350 this.mode == 'local' ? 10 : 250);
11353 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11355 if(this.typeAhead){
11356 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11358 if(this.editable !== false){
11359 this.inputEl().on("keyup", this.onKeyUp, this);
11361 if(this.forceSelection){
11362 this.inputEl().on('blur', this.doForce, this);
11366 this.choices = this.el.select('ul.select2-choices', true).first();
11367 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11371 initTickableEvents: function()
11375 if(this.hiddenName){
11377 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11379 this.hiddenField.dom.value =
11380 this.hiddenValue !== undefined ? this.hiddenValue :
11381 this.value !== undefined ? this.value : '';
11383 // prevent input submission
11384 this.el.dom.removeAttribute('name');
11385 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11390 // this.list = this.el.select('ul.dropdown-menu',true).first();
11392 this.choices = this.el.select('ul.select2-choices', true).first();
11393 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11394 if(this.triggerList){
11395 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11398 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11399 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11401 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11402 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11404 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11405 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11407 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11408 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11409 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11412 this.cancelBtn.hide();
11417 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11418 _this.list.setWidth(lw);
11421 this.list.on('mouseover', this.onViewOver, this);
11422 this.list.on('mousemove', this.onViewMove, this);
11424 this.list.on('scroll', this.onViewScroll, this);
11427 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>';
11430 this.view = new Roo.View(this.list, this.tpl, {
11431 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11434 //this.view.wrapEl.setDisplayed(false);
11435 this.view.on('click', this.onViewClick, this);
11439 this.store.on('beforeload', this.onBeforeLoad, this);
11440 this.store.on('load', this.onLoad, this);
11441 this.store.on('loadexception', this.onLoadException, this);
11444 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11445 "up" : function(e){
11446 this.inKeyMode = true;
11450 "down" : function(e){
11451 this.inKeyMode = true;
11455 "enter" : function(e){
11456 if(this.fireEvent("specialkey", this, e)){
11457 this.onViewClick(false);
11463 "esc" : function(e){
11464 this.onTickableFooterButtonClick(e, false, false);
11467 "tab" : function(e){
11468 this.fireEvent("specialkey", this, e);
11470 this.onTickableFooterButtonClick(e, false, false);
11477 doRelay : function(e, fn, key){
11478 if(this.scope.isExpanded()){
11479 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11488 this.queryDelay = Math.max(this.queryDelay || 10,
11489 this.mode == 'local' ? 10 : 250);
11492 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11494 if(this.typeAhead){
11495 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11498 if(this.editable !== false){
11499 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11504 onDestroy : function(){
11506 this.view.setStore(null);
11507 this.view.el.removeAllListeners();
11508 this.view.el.remove();
11509 this.view.purgeListeners();
11512 this.list.dom.innerHTML = '';
11516 this.store.un('beforeload', this.onBeforeLoad, this);
11517 this.store.un('load', this.onLoad, this);
11518 this.store.un('loadexception', this.onLoadException, this);
11520 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11524 fireKey : function(e){
11525 if(e.isNavKeyPress() && !this.list.isVisible()){
11526 this.fireEvent("specialkey", this, e);
11531 onResize: function(w, h){
11532 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11534 // if(typeof w != 'number'){
11535 // // we do not handle it!?!?
11538 // var tw = this.trigger.getWidth();
11539 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11540 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11542 // this.inputEl().setWidth( this.adjustWidth('input', x));
11544 // //this.trigger.setStyle('left', x+'px');
11546 // if(this.list && this.listWidth === undefined){
11547 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11548 // this.list.setWidth(lw);
11549 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11557 * Allow or prevent the user from directly editing the field text. If false is passed,
11558 * the user will only be able to select from the items defined in the dropdown list. This method
11559 * is the runtime equivalent of setting the 'editable' config option at config time.
11560 * @param {Boolean} value True to allow the user to directly edit the field text
11562 setEditable : function(value){
11563 if(value == this.editable){
11566 this.editable = value;
11568 this.inputEl().dom.setAttribute('readOnly', true);
11569 this.inputEl().on('mousedown', this.onTriggerClick, this);
11570 this.inputEl().addClass('x-combo-noedit');
11572 this.inputEl().dom.setAttribute('readOnly', false);
11573 this.inputEl().un('mousedown', this.onTriggerClick, this);
11574 this.inputEl().removeClass('x-combo-noedit');
11580 onBeforeLoad : function(combo,opts){
11581 if(!this.hasFocus){
11585 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11587 this.restrictHeight();
11588 this.selectedIndex = -1;
11592 onLoad : function(){
11594 this.hasQuery = false;
11596 if(!this.hasFocus){
11600 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11601 this.loading.hide();
11604 if(this.store.getCount() > 0){
11606 this.restrictHeight();
11607 if(this.lastQuery == this.allQuery){
11608 if(this.editable && !this.tickable){
11609 this.inputEl().dom.select();
11613 !this.selectByValue(this.value, true) &&
11616 !this.store.lastOptions ||
11617 typeof(this.store.lastOptions.add) == 'undefined' ||
11618 this.store.lastOptions.add != true
11621 this.select(0, true);
11624 if(this.autoFocus){
11627 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11628 this.taTask.delay(this.typeAheadDelay);
11632 this.onEmptyResults();
11638 onLoadException : function()
11640 this.hasQuery = false;
11642 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11643 this.loading.hide();
11646 if(this.tickable && this.editable){
11652 Roo.log(this.store.reader.jsonData);
11653 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11655 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11661 onTypeAhead : function(){
11662 if(this.store.getCount() > 0){
11663 var r = this.store.getAt(0);
11664 var newValue = r.data[this.displayField];
11665 var len = newValue.length;
11666 var selStart = this.getRawValue().length;
11668 if(selStart != len){
11669 this.setRawValue(newValue);
11670 this.selectText(selStart, newValue.length);
11676 onSelect : function(record, index){
11678 if(this.fireEvent('beforeselect', this, record, index) !== false){
11680 this.setFromData(index > -1 ? record.data : false);
11683 this.fireEvent('select', this, record, index);
11688 * Returns the currently selected field value or empty string if no value is set.
11689 * @return {String} value The selected value
11691 getValue : function(){
11694 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11697 if(this.valueField){
11698 return typeof this.value != 'undefined' ? this.value : '';
11700 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11705 * Clears any text/value currently set in the field
11707 clearValue : function(){
11708 if(this.hiddenField){
11709 this.hiddenField.dom.value = '';
11712 this.setRawValue('');
11713 this.lastSelectionText = '';
11714 this.lastData = false;
11719 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11720 * will be displayed in the field. If the value does not match the data value of an existing item,
11721 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11722 * Otherwise the field will be blank (although the value will still be set).
11723 * @param {String} value The value to match
11725 setValue : function(v){
11732 if(this.valueField){
11733 var r = this.findRecord(this.valueField, v);
11735 text = r.data[this.displayField];
11736 }else if(this.valueNotFoundText !== undefined){
11737 text = this.valueNotFoundText;
11740 this.lastSelectionText = text;
11741 if(this.hiddenField){
11742 this.hiddenField.dom.value = v;
11744 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11748 * @property {Object} the last set data for the element
11753 * Sets the value of the field based on a object which is related to the record format for the store.
11754 * @param {Object} value the value to set as. or false on reset?
11756 setFromData : function(o){
11763 var dv = ''; // display value
11764 var vv = ''; // value value..
11766 if (this.displayField) {
11767 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11769 // this is an error condition!!!
11770 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11773 if(this.valueField){
11774 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11777 if(this.hiddenField){
11778 this.hiddenField.dom.value = vv;
11780 this.lastSelectionText = dv;
11781 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11785 // no hidden field.. - we store the value in 'value', but still display
11786 // display field!!!!
11787 this.lastSelectionText = dv;
11788 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11794 reset : function(){
11795 // overridden so that last data is reset..
11802 this.setValue(this.originalValue);
11803 this.clearInvalid();
11804 this.lastData = false;
11806 this.view.clearSelections();
11810 findRecord : function(prop, value){
11812 if(this.store.getCount() > 0){
11813 this.store.each(function(r){
11814 if(r.data[prop] == value){
11824 getName: function()
11826 // returns hidden if it's set..
11827 if (!this.rendered) {return ''};
11828 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11832 onViewMove : function(e, t){
11833 this.inKeyMode = false;
11837 onViewOver : function(e, t){
11838 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11841 var item = this.view.findItemFromChild(t);
11844 var index = this.view.indexOf(item);
11845 this.select(index, false);
11850 onViewClick : function(view, doFocus, el, e)
11852 var index = this.view.getSelectedIndexes()[0];
11854 var r = this.store.getAt(index);
11858 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11865 Roo.each(this.tickItems, function(v,k){
11867 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11868 _this.tickItems.splice(k, 1);
11870 if(typeof(e) == 'undefined' && view == false){
11871 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11883 this.tickItems.push(r.data);
11885 if(typeof(e) == 'undefined' && view == false){
11886 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11893 this.onSelect(r, index);
11895 if(doFocus !== false && !this.blockFocus){
11896 this.inputEl().focus();
11901 restrictHeight : function(){
11902 //this.innerList.dom.style.height = '';
11903 //var inner = this.innerList.dom;
11904 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11905 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11906 //this.list.beginUpdate();
11907 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11908 this.list.alignTo(this.inputEl(), this.listAlign);
11909 this.list.alignTo(this.inputEl(), this.listAlign);
11910 //this.list.endUpdate();
11914 onEmptyResults : function(){
11916 if(this.tickable && this.editable){
11917 this.restrictHeight();
11925 * Returns true if the dropdown list is expanded, else false.
11927 isExpanded : function(){
11928 return this.list.isVisible();
11932 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11933 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11934 * @param {String} value The data value of the item to select
11935 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11936 * selected item if it is not currently in view (defaults to true)
11937 * @return {Boolean} True if the value matched an item in the list, else false
11939 selectByValue : function(v, scrollIntoView){
11940 if(v !== undefined && v !== null){
11941 var r = this.findRecord(this.valueField || this.displayField, v);
11943 this.select(this.store.indexOf(r), scrollIntoView);
11951 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11952 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11953 * @param {Number} index The zero-based index of the list item to select
11954 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11955 * selected item if it is not currently in view (defaults to true)
11957 select : function(index, scrollIntoView){
11958 this.selectedIndex = index;
11959 this.view.select(index);
11960 if(scrollIntoView !== false){
11961 var el = this.view.getNode(index);
11963 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11966 this.list.scrollChildIntoView(el, false);
11972 selectNext : function(){
11973 var ct = this.store.getCount();
11975 if(this.selectedIndex == -1){
11977 }else if(this.selectedIndex < ct-1){
11978 this.select(this.selectedIndex+1);
11984 selectPrev : function(){
11985 var ct = this.store.getCount();
11987 if(this.selectedIndex == -1){
11989 }else if(this.selectedIndex != 0){
11990 this.select(this.selectedIndex-1);
11996 onKeyUp : function(e){
11997 if(this.editable !== false && !e.isSpecialKey()){
11998 this.lastKey = e.getKey();
11999 this.dqTask.delay(this.queryDelay);
12004 validateBlur : function(){
12005 return !this.list || !this.list.isVisible();
12009 initQuery : function(){
12011 var v = this.getRawValue();
12013 if(this.tickable && this.editable){
12014 v = this.tickableInputEl().getValue();
12021 doForce : function(){
12022 if(this.inputEl().dom.value.length > 0){
12023 this.inputEl().dom.value =
12024 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12030 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12031 * query allowing the query action to be canceled if needed.
12032 * @param {String} query The SQL query to execute
12033 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12034 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12035 * saved in the current store (defaults to false)
12037 doQuery : function(q, forceAll){
12039 if(q === undefined || q === null){
12044 forceAll: forceAll,
12048 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12053 forceAll = qe.forceAll;
12054 if(forceAll === true || (q.length >= this.minChars)){
12056 this.hasQuery = true;
12058 if(this.lastQuery != q || this.alwaysQuery){
12059 this.lastQuery = q;
12060 if(this.mode == 'local'){
12061 this.selectedIndex = -1;
12063 this.store.clearFilter();
12065 this.store.filter(this.displayField, q);
12070 this.store.baseParams[this.queryParam] = q;
12072 var options = {params : this.getParams(q)};
12075 options.add = true;
12076 options.params.start = this.page * this.pageSize;
12079 this.store.load(options);
12082 * this code will make the page width larger, at the beginning, the list not align correctly,
12083 * we should expand the list on onLoad
12084 * so command out it
12089 this.selectedIndex = -1;
12094 this.loadNext = false;
12098 getParams : function(q){
12100 //p[this.queryParam] = q;
12104 p.limit = this.pageSize;
12110 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12112 collapse : function(){
12113 if(!this.isExpanded()){
12120 this.hasFocus = false;
12122 this.cancelBtn.hide();
12123 this.trigger.show();
12126 this.tickableInputEl().dom.value = '';
12127 this.tickableInputEl().blur();
12132 Roo.get(document).un('mousedown', this.collapseIf, this);
12133 Roo.get(document).un('mousewheel', this.collapseIf, this);
12134 if (!this.editable) {
12135 Roo.get(document).un('keydown', this.listKeyPress, this);
12137 this.fireEvent('collapse', this);
12141 collapseIf : function(e){
12142 var in_combo = e.within(this.el);
12143 var in_list = e.within(this.list);
12144 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12146 if (in_combo || in_list || is_list) {
12147 //e.stopPropagation();
12152 this.onTickableFooterButtonClick(e, false, false);
12160 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12162 expand : function(){
12164 if(this.isExpanded() || !this.hasFocus){
12168 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12169 this.list.setWidth(lw);
12176 this.restrictHeight();
12180 this.tickItems = Roo.apply([], this.item);
12183 this.cancelBtn.show();
12184 this.trigger.hide();
12187 this.tickableInputEl().focus();
12192 Roo.get(document).on('mousedown', this.collapseIf, this);
12193 Roo.get(document).on('mousewheel', this.collapseIf, this);
12194 if (!this.editable) {
12195 Roo.get(document).on('keydown', this.listKeyPress, this);
12198 this.fireEvent('expand', this);
12202 // Implements the default empty TriggerField.onTriggerClick function
12203 onTriggerClick : function(e)
12205 Roo.log('trigger click');
12207 if(this.disabled || !this.triggerList){
12212 this.loadNext = false;
12214 if(this.isExpanded()){
12216 if (!this.blockFocus) {
12217 this.inputEl().focus();
12221 this.hasFocus = true;
12222 if(this.triggerAction == 'all') {
12223 this.doQuery(this.allQuery, true);
12225 this.doQuery(this.getRawValue());
12227 if (!this.blockFocus) {
12228 this.inputEl().focus();
12233 onTickableTriggerClick : function(e)
12240 this.loadNext = false;
12241 this.hasFocus = true;
12243 if(this.triggerAction == 'all') {
12244 this.doQuery(this.allQuery, true);
12246 this.doQuery(this.getRawValue());
12250 onSearchFieldClick : function(e)
12252 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12253 this.onTickableFooterButtonClick(e, false, false);
12257 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12262 this.loadNext = false;
12263 this.hasFocus = true;
12265 if(this.triggerAction == 'all') {
12266 this.doQuery(this.allQuery, true);
12268 this.doQuery(this.getRawValue());
12272 listKeyPress : function(e)
12274 //Roo.log('listkeypress');
12275 // scroll to first matching element based on key pres..
12276 if (e.isSpecialKey()) {
12279 var k = String.fromCharCode(e.getKey()).toUpperCase();
12282 var csel = this.view.getSelectedNodes();
12283 var cselitem = false;
12285 var ix = this.view.indexOf(csel[0]);
12286 cselitem = this.store.getAt(ix);
12287 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12293 this.store.each(function(v) {
12295 // start at existing selection.
12296 if (cselitem.id == v.id) {
12302 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12303 match = this.store.indexOf(v);
12309 if (match === false) {
12310 return true; // no more action?
12313 this.view.select(match);
12314 var sn = Roo.get(this.view.getSelectedNodes()[0])
12315 sn.scrollIntoView(sn.dom.parentNode, false);
12318 onViewScroll : function(e, t){
12320 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){
12324 this.hasQuery = true;
12326 this.loading = this.list.select('.loading', true).first();
12328 if(this.loading === null){
12329 this.list.createChild({
12331 cls: 'loading select2-more-results select2-active',
12332 html: 'Loading more results...'
12335 this.loading = this.list.select('.loading', true).first();
12337 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12339 this.loading.hide();
12342 this.loading.show();
12347 this.loadNext = true;
12349 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12354 addItem : function(o)
12356 var dv = ''; // display value
12358 if (this.displayField) {
12359 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12361 // this is an error condition!!!
12362 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12369 var choice = this.choices.createChild({
12371 cls: 'select2-search-choice',
12380 cls: 'select2-search-choice-close',
12385 }, this.searchField);
12387 var close = choice.select('a.select2-search-choice-close', true).first()
12389 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12397 this.inputEl().dom.value = '';
12402 onRemoveItem : function(e, _self, o)
12404 e.preventDefault();
12406 this.lastItem = Roo.apply([], this.item);
12408 var index = this.item.indexOf(o.data) * 1;
12411 Roo.log('not this item?!');
12415 this.item.splice(index, 1);
12420 this.fireEvent('remove', this, e);
12426 syncValue : function()
12428 if(!this.item.length){
12435 Roo.each(this.item, function(i){
12436 if(_this.valueField){
12437 value.push(i[_this.valueField]);
12444 this.value = value.join(',');
12446 if(this.hiddenField){
12447 this.hiddenField.dom.value = this.value;
12451 clearItem : function()
12453 if(!this.multiple){
12459 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12468 inputEl: function ()
12471 return this.searchField;
12473 return this.el.select('input.form-control',true).first();
12477 onTickableFooterButtonClick : function(e, btn, el)
12479 e.preventDefault();
12481 this.lastItem = Roo.apply([], this.item);
12483 if(btn && btn.name == 'cancel'){
12484 this.tickItems = Roo.apply([], this.item);
12493 Roo.each(this.tickItems, function(o){
12501 validate : function()
12503 var v = this.getRawValue();
12506 v = this.getValue();
12509 if(this.disabled || this.allowBlank || v.length){
12514 this.markInvalid();
12518 tickableInputEl : function()
12520 if(!this.tickable || !this.editable){
12521 return this.inputEl();
12524 return this.inputEl().select('.select2-search-field-input', true).first();
12530 * @cfg {Boolean} grow
12534 * @cfg {Number} growMin
12538 * @cfg {Number} growMax
12548 * Ext JS Library 1.1.1
12549 * Copyright(c) 2006-2007, Ext JS, LLC.
12551 * Originally Released Under LGPL - original licence link has changed is not relivant.
12554 * <script type="text/javascript">
12559 * @extends Roo.util.Observable
12560 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12561 * This class also supports single and multi selection modes. <br>
12562 * Create a data model bound view:
12564 var store = new Roo.data.Store(...);
12566 var view = new Roo.View({
12568 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12570 singleSelect: true,
12571 selectedClass: "ydataview-selected",
12575 // listen for node click?
12576 view.on("click", function(vw, index, node, e){
12577 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12581 dataModel.load("foobar.xml");
12583 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12585 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12586 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12588 * Note: old style constructor is still suported (container, template, config)
12591 * Create a new View
12592 * @param {Object} config The config object
12595 Roo.View = function(config, depreciated_tpl, depreciated_config){
12597 this.parent = false;
12599 if (typeof(depreciated_tpl) == 'undefined') {
12600 // new way.. - universal constructor.
12601 Roo.apply(this, config);
12602 this.el = Roo.get(this.el);
12605 this.el = Roo.get(config);
12606 this.tpl = depreciated_tpl;
12607 Roo.apply(this, depreciated_config);
12609 this.wrapEl = this.el.wrap().wrap();
12610 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12613 if(typeof(this.tpl) == "string"){
12614 this.tpl = new Roo.Template(this.tpl);
12616 // support xtype ctors..
12617 this.tpl = new Roo.factory(this.tpl, Roo);
12621 this.tpl.compile();
12626 * @event beforeclick
12627 * Fires before a click is processed. Returns false to cancel the default action.
12628 * @param {Roo.View} this
12629 * @param {Number} index The index of the target node
12630 * @param {HTMLElement} node The target node
12631 * @param {Roo.EventObject} e The raw event object
12633 "beforeclick" : true,
12636 * Fires when a template node is clicked.
12637 * @param {Roo.View} this
12638 * @param {Number} index The index of the target node
12639 * @param {HTMLElement} node The target node
12640 * @param {Roo.EventObject} e The raw event object
12645 * Fires when a template node is double clicked.
12646 * @param {Roo.View} this
12647 * @param {Number} index The index of the target node
12648 * @param {HTMLElement} node The target node
12649 * @param {Roo.EventObject} e The raw event object
12653 * @event contextmenu
12654 * Fires when a template node is right clicked.
12655 * @param {Roo.View} this
12656 * @param {Number} index The index of the target node
12657 * @param {HTMLElement} node The target node
12658 * @param {Roo.EventObject} e The raw event object
12660 "contextmenu" : true,
12662 * @event selectionchange
12663 * Fires when the selected nodes change.
12664 * @param {Roo.View} this
12665 * @param {Array} selections Array of the selected nodes
12667 "selectionchange" : true,
12670 * @event beforeselect
12671 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12672 * @param {Roo.View} this
12673 * @param {HTMLElement} node The node to be selected
12674 * @param {Array} selections Array of currently selected nodes
12676 "beforeselect" : true,
12678 * @event preparedata
12679 * Fires on every row to render, to allow you to change the data.
12680 * @param {Roo.View} this
12681 * @param {Object} data to be rendered (change this)
12683 "preparedata" : true
12691 "click": this.onClick,
12692 "dblclick": this.onDblClick,
12693 "contextmenu": this.onContextMenu,
12697 this.selections = [];
12699 this.cmp = new Roo.CompositeElementLite([]);
12701 this.store = Roo.factory(this.store, Roo.data);
12702 this.setStore(this.store, true);
12705 if ( this.footer && this.footer.xtype) {
12707 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12709 this.footer.dataSource = this.store
12710 this.footer.container = fctr;
12711 this.footer = Roo.factory(this.footer, Roo);
12712 fctr.insertFirst(this.el);
12714 // this is a bit insane - as the paging toolbar seems to detach the el..
12715 // dom.parentNode.parentNode.parentNode
12716 // they get detached?
12720 Roo.View.superclass.constructor.call(this);
12725 Roo.extend(Roo.View, Roo.util.Observable, {
12728 * @cfg {Roo.data.Store} store Data store to load data from.
12733 * @cfg {String|Roo.Element} el The container element.
12738 * @cfg {String|Roo.Template} tpl The template used by this View
12742 * @cfg {String} dataName the named area of the template to use as the data area
12743 * Works with domtemplates roo-name="name"
12747 * @cfg {String} selectedClass The css class to add to selected nodes
12749 selectedClass : "x-view-selected",
12751 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12756 * @cfg {String} text to display on mask (default Loading)
12760 * @cfg {Boolean} multiSelect Allow multiple selection
12762 multiSelect : false,
12764 * @cfg {Boolean} singleSelect Allow single selection
12766 singleSelect: false,
12769 * @cfg {Boolean} toggleSelect - selecting
12771 toggleSelect : false,
12774 * @cfg {Boolean} tickable - selecting
12779 * Returns the element this view is bound to.
12780 * @return {Roo.Element}
12782 getEl : function(){
12783 return this.wrapEl;
12789 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12791 refresh : function(){
12792 //Roo.log('refresh');
12795 // if we are using something like 'domtemplate', then
12796 // the what gets used is:
12797 // t.applySubtemplate(NAME, data, wrapping data..)
12798 // the outer template then get' applied with
12799 // the store 'extra data'
12800 // and the body get's added to the
12801 // roo-name="data" node?
12802 // <span class='roo-tpl-{name}'></span> ?????
12806 this.clearSelections();
12807 this.el.update("");
12809 var records = this.store.getRange();
12810 if(records.length < 1) {
12812 // is this valid?? = should it render a template??
12814 this.el.update(this.emptyText);
12818 if (this.dataName) {
12819 this.el.update(t.apply(this.store.meta)); //????
12820 el = this.el.child('.roo-tpl-' + this.dataName);
12823 for(var i = 0, len = records.length; i < len; i++){
12824 var data = this.prepareData(records[i].data, i, records[i]);
12825 this.fireEvent("preparedata", this, data, i, records[i]);
12827 var d = Roo.apply({}, data);
12830 Roo.apply(d, {'roo-id' : Roo.id()});
12834 Roo.each(this.parent.item, function(item){
12835 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12838 Roo.apply(d, {'roo-data-checked' : 'checked'});
12842 html[html.length] = Roo.util.Format.trim(
12844 t.applySubtemplate(this.dataName, d, this.store.meta) :
12851 el.update(html.join(""));
12852 this.nodes = el.dom.childNodes;
12853 this.updateIndexes(0);
12858 * Function to override to reformat the data that is sent to
12859 * the template for each node.
12860 * DEPRICATED - use the preparedata event handler.
12861 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12862 * a JSON object for an UpdateManager bound view).
12864 prepareData : function(data, index, record)
12866 this.fireEvent("preparedata", this, data, index, record);
12870 onUpdate : function(ds, record){
12871 // Roo.log('on update');
12872 this.clearSelections();
12873 var index = this.store.indexOf(record);
12874 var n = this.nodes[index];
12875 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12876 n.parentNode.removeChild(n);
12877 this.updateIndexes(index, index);
12883 onAdd : function(ds, records, index)
12885 //Roo.log(['on Add', ds, records, index] );
12886 this.clearSelections();
12887 if(this.nodes.length == 0){
12891 var n = this.nodes[index];
12892 for(var i = 0, len = records.length; i < len; i++){
12893 var d = this.prepareData(records[i].data, i, records[i]);
12895 this.tpl.insertBefore(n, d);
12898 this.tpl.append(this.el, d);
12901 this.updateIndexes(index);
12904 onRemove : function(ds, record, index){
12905 // Roo.log('onRemove');
12906 this.clearSelections();
12907 var el = this.dataName ?
12908 this.el.child('.roo-tpl-' + this.dataName) :
12911 el.dom.removeChild(this.nodes[index]);
12912 this.updateIndexes(index);
12916 * Refresh an individual node.
12917 * @param {Number} index
12919 refreshNode : function(index){
12920 this.onUpdate(this.store, this.store.getAt(index));
12923 updateIndexes : function(startIndex, endIndex){
12924 var ns = this.nodes;
12925 startIndex = startIndex || 0;
12926 endIndex = endIndex || ns.length - 1;
12927 for(var i = startIndex; i <= endIndex; i++){
12928 ns[i].nodeIndex = i;
12933 * Changes the data store this view uses and refresh the view.
12934 * @param {Store} store
12936 setStore : function(store, initial){
12937 if(!initial && this.store){
12938 this.store.un("datachanged", this.refresh);
12939 this.store.un("add", this.onAdd);
12940 this.store.un("remove", this.onRemove);
12941 this.store.un("update", this.onUpdate);
12942 this.store.un("clear", this.refresh);
12943 this.store.un("beforeload", this.onBeforeLoad);
12944 this.store.un("load", this.onLoad);
12945 this.store.un("loadexception", this.onLoad);
12949 store.on("datachanged", this.refresh, this);
12950 store.on("add", this.onAdd, this);
12951 store.on("remove", this.onRemove, this);
12952 store.on("update", this.onUpdate, this);
12953 store.on("clear", this.refresh, this);
12954 store.on("beforeload", this.onBeforeLoad, this);
12955 store.on("load", this.onLoad, this);
12956 store.on("loadexception", this.onLoad, this);
12964 * onbeforeLoad - masks the loading area.
12967 onBeforeLoad : function(store,opts)
12969 //Roo.log('onBeforeLoad');
12971 this.el.update("");
12973 this.el.mask(this.mask ? this.mask : "Loading" );
12975 onLoad : function ()
12982 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12983 * @param {HTMLElement} node
12984 * @return {HTMLElement} The template node
12986 findItemFromChild : function(node){
12987 var el = this.dataName ?
12988 this.el.child('.roo-tpl-' + this.dataName,true) :
12991 if(!node || node.parentNode == el){
12994 var p = node.parentNode;
12995 while(p && p != el){
12996 if(p.parentNode == el){
13005 onClick : function(e){
13006 var item = this.findItemFromChild(e.getTarget());
13008 var index = this.indexOf(item);
13009 if(this.onItemClick(item, index, e) !== false){
13010 this.fireEvent("click", this, index, item, e);
13013 this.clearSelections();
13018 onContextMenu : function(e){
13019 var item = this.findItemFromChild(e.getTarget());
13021 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13026 onDblClick : function(e){
13027 var item = this.findItemFromChild(e.getTarget());
13029 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13033 onItemClick : function(item, index, e)
13035 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13038 if (this.toggleSelect) {
13039 var m = this.isSelected(item) ? 'unselect' : 'select';
13042 _t[m](item, true, false);
13045 if(this.multiSelect || this.singleSelect){
13046 if(this.multiSelect && e.shiftKey && this.lastSelection){
13047 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13049 this.select(item, this.multiSelect && e.ctrlKey);
13050 this.lastSelection = item;
13053 if(!this.tickable){
13054 e.preventDefault();
13062 * Get the number of selected nodes.
13065 getSelectionCount : function(){
13066 return this.selections.length;
13070 * Get the currently selected nodes.
13071 * @return {Array} An array of HTMLElements
13073 getSelectedNodes : function(){
13074 return this.selections;
13078 * Get the indexes of the selected nodes.
13081 getSelectedIndexes : function(){
13082 var indexes = [], s = this.selections;
13083 for(var i = 0, len = s.length; i < len; i++){
13084 indexes.push(s[i].nodeIndex);
13090 * Clear all selections
13091 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13093 clearSelections : function(suppressEvent){
13094 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13095 this.cmp.elements = this.selections;
13096 this.cmp.removeClass(this.selectedClass);
13097 this.selections = [];
13098 if(!suppressEvent){
13099 this.fireEvent("selectionchange", this, this.selections);
13105 * Returns true if the passed node is selected
13106 * @param {HTMLElement/Number} node The node or node index
13107 * @return {Boolean}
13109 isSelected : function(node){
13110 var s = this.selections;
13114 node = this.getNode(node);
13115 return s.indexOf(node) !== -1;
13120 * @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
13121 * @param {Boolean} keepExisting (optional) true to keep existing selections
13122 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13124 select : function(nodeInfo, keepExisting, suppressEvent){
13125 if(nodeInfo instanceof Array){
13127 this.clearSelections(true);
13129 for(var i = 0, len = nodeInfo.length; i < len; i++){
13130 this.select(nodeInfo[i], true, true);
13134 var node = this.getNode(nodeInfo);
13135 if(!node || this.isSelected(node)){
13136 return; // already selected.
13139 this.clearSelections(true);
13142 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13143 Roo.fly(node).addClass(this.selectedClass);
13144 this.selections.push(node);
13145 if(!suppressEvent){
13146 this.fireEvent("selectionchange", this, this.selections);
13154 * @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
13155 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13156 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13158 unselect : function(nodeInfo, keepExisting, suppressEvent)
13160 if(nodeInfo instanceof Array){
13161 Roo.each(this.selections, function(s) {
13162 this.unselect(s, nodeInfo);
13166 var node = this.getNode(nodeInfo);
13167 if(!node || !this.isSelected(node)){
13168 //Roo.log("not selected");
13169 return; // not selected.
13173 Roo.each(this.selections, function(s) {
13175 Roo.fly(node).removeClass(this.selectedClass);
13182 this.selections= ns;
13183 this.fireEvent("selectionchange", this, this.selections);
13187 * Gets a template node.
13188 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13189 * @return {HTMLElement} The node or null if it wasn't found
13191 getNode : function(nodeInfo){
13192 if(typeof nodeInfo == "string"){
13193 return document.getElementById(nodeInfo);
13194 }else if(typeof nodeInfo == "number"){
13195 return this.nodes[nodeInfo];
13201 * Gets a range template nodes.
13202 * @param {Number} startIndex
13203 * @param {Number} endIndex
13204 * @return {Array} An array of nodes
13206 getNodes : function(start, end){
13207 var ns = this.nodes;
13208 start = start || 0;
13209 end = typeof end == "undefined" ? ns.length - 1 : end;
13212 for(var i = start; i <= end; i++){
13216 for(var i = start; i >= end; i--){
13224 * Finds the index of the passed node
13225 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13226 * @return {Number} The index of the node or -1
13228 indexOf : function(node){
13229 node = this.getNode(node);
13230 if(typeof node.nodeIndex == "number"){
13231 return node.nodeIndex;
13233 var ns = this.nodes;
13234 for(var i = 0, len = ns.length; i < len; i++){
13245 * based on jquery fullcalendar
13249 Roo.bootstrap = Roo.bootstrap || {};
13251 * @class Roo.bootstrap.Calendar
13252 * @extends Roo.bootstrap.Component
13253 * Bootstrap Calendar class
13254 * @cfg {Boolean} loadMask (true|false) default false
13255 * @cfg {Object} header generate the user specific header of the calendar, default false
13258 * Create a new Container
13259 * @param {Object} config The config object
13264 Roo.bootstrap.Calendar = function(config){
13265 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13269 * Fires when a date is selected
13270 * @param {DatePicker} this
13271 * @param {Date} date The selected date
13275 * @event monthchange
13276 * Fires when the displayed month changes
13277 * @param {DatePicker} this
13278 * @param {Date} date The selected month
13280 'monthchange': true,
13282 * @event evententer
13283 * Fires when mouse over an event
13284 * @param {Calendar} this
13285 * @param {event} Event
13287 'evententer': true,
13289 * @event eventleave
13290 * Fires when the mouse leaves an
13291 * @param {Calendar} this
13294 'eventleave': true,
13296 * @event eventclick
13297 * Fires when the mouse click an
13298 * @param {Calendar} this
13307 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13310 * @cfg {Number} startDay
13311 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13319 getAutoCreate : function(){
13322 var fc_button = function(name, corner, style, content ) {
13323 return Roo.apply({},{
13325 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13327 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13330 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13341 style : 'width:100%',
13348 cls : 'fc-header-left',
13350 fc_button('prev', 'left', 'arrow', '‹' ),
13351 fc_button('next', 'right', 'arrow', '›' ),
13352 { tag: 'span', cls: 'fc-header-space' },
13353 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13361 cls : 'fc-header-center',
13365 cls: 'fc-header-title',
13368 html : 'month / year'
13376 cls : 'fc-header-right',
13378 /* fc_button('month', 'left', '', 'month' ),
13379 fc_button('week', '', '', 'week' ),
13380 fc_button('day', 'right', '', 'day' )
13392 header = this.header;
13395 var cal_heads = function() {
13397 // fixme - handle this.
13399 for (var i =0; i < Date.dayNames.length; i++) {
13400 var d = Date.dayNames[i];
13403 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13404 html : d.substring(0,3)
13408 ret[0].cls += ' fc-first';
13409 ret[6].cls += ' fc-last';
13412 var cal_cell = function(n) {
13415 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13420 cls: 'fc-day-number',
13424 cls: 'fc-day-content',
13428 style: 'position: relative;' // height: 17px;
13440 var cal_rows = function() {
13443 for (var r = 0; r < 6; r++) {
13450 for (var i =0; i < Date.dayNames.length; i++) {
13451 var d = Date.dayNames[i];
13452 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13455 row.cn[0].cls+=' fc-first';
13456 row.cn[0].cn[0].style = 'min-height:90px';
13457 row.cn[6].cls+=' fc-last';
13461 ret[0].cls += ' fc-first';
13462 ret[4].cls += ' fc-prev-last';
13463 ret[5].cls += ' fc-last';
13470 cls: 'fc-border-separate',
13471 style : 'width:100%',
13479 cls : 'fc-first fc-last',
13497 cls : 'fc-content',
13498 style : "position: relative;",
13501 cls : 'fc-view fc-view-month fc-grid',
13502 style : 'position: relative',
13503 unselectable : 'on',
13506 cls : 'fc-event-container',
13507 style : 'position:absolute;z-index:8;top:0;left:0;'
13525 initEvents : function()
13528 throw "can not find store for calendar";
13534 style: "text-align:center",
13538 style: "background-color:white;width:50%;margin:250 auto",
13542 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13553 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13555 var size = this.el.select('.fc-content', true).first().getSize();
13556 this.maskEl.setSize(size.width, size.height);
13557 this.maskEl.enableDisplayMode("block");
13558 if(!this.loadMask){
13559 this.maskEl.hide();
13562 this.store = Roo.factory(this.store, Roo.data);
13563 this.store.on('load', this.onLoad, this);
13564 this.store.on('beforeload', this.onBeforeLoad, this);
13568 this.cells = this.el.select('.fc-day',true);
13569 //Roo.log(this.cells);
13570 this.textNodes = this.el.query('.fc-day-number');
13571 this.cells.addClassOnOver('fc-state-hover');
13573 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13574 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13575 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13576 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13578 this.on('monthchange', this.onMonthChange, this);
13580 this.update(new Date().clearTime());
13583 resize : function() {
13584 var sz = this.el.getSize();
13586 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13587 this.el.select('.fc-day-content div',true).setHeight(34);
13592 showPrevMonth : function(e){
13593 this.update(this.activeDate.add("mo", -1));
13595 showToday : function(e){
13596 this.update(new Date().clearTime());
13599 showNextMonth : function(e){
13600 this.update(this.activeDate.add("mo", 1));
13604 showPrevYear : function(){
13605 this.update(this.activeDate.add("y", -1));
13609 showNextYear : function(){
13610 this.update(this.activeDate.add("y", 1));
13615 update : function(date)
13617 var vd = this.activeDate;
13618 this.activeDate = date;
13619 // if(vd && this.el){
13620 // var t = date.getTime();
13621 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13622 // Roo.log('using add remove');
13624 // this.fireEvent('monthchange', this, date);
13626 // this.cells.removeClass("fc-state-highlight");
13627 // this.cells.each(function(c){
13628 // if(c.dateValue == t){
13629 // c.addClass("fc-state-highlight");
13630 // setTimeout(function(){
13631 // try{c.dom.firstChild.focus();}catch(e){}
13641 var days = date.getDaysInMonth();
13643 var firstOfMonth = date.getFirstDateOfMonth();
13644 var startingPos = firstOfMonth.getDay()-this.startDay;
13646 if(startingPos < this.startDay){
13650 var pm = date.add(Date.MONTH, -1);
13651 var prevStart = pm.getDaysInMonth()-startingPos;
13653 this.cells = this.el.select('.fc-day',true);
13654 this.textNodes = this.el.query('.fc-day-number');
13655 this.cells.addClassOnOver('fc-state-hover');
13657 var cells = this.cells.elements;
13658 var textEls = this.textNodes;
13660 Roo.each(cells, function(cell){
13661 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13664 days += startingPos;
13666 // convert everything to numbers so it's fast
13667 var day = 86400000;
13668 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13671 //Roo.log(prevStart);
13673 var today = new Date().clearTime().getTime();
13674 var sel = date.clearTime().getTime();
13675 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13676 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13677 var ddMatch = this.disabledDatesRE;
13678 var ddText = this.disabledDatesText;
13679 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13680 var ddaysText = this.disabledDaysText;
13681 var format = this.format;
13683 var setCellClass = function(cal, cell){
13687 //Roo.log('set Cell Class');
13689 var t = d.getTime();
13693 cell.dateValue = t;
13695 cell.className += " fc-today";
13696 cell.className += " fc-state-highlight";
13697 cell.title = cal.todayText;
13700 // disable highlight in other month..
13701 //cell.className += " fc-state-highlight";
13706 cell.className = " fc-state-disabled";
13707 cell.title = cal.minText;
13711 cell.className = " fc-state-disabled";
13712 cell.title = cal.maxText;
13716 if(ddays.indexOf(d.getDay()) != -1){
13717 cell.title = ddaysText;
13718 cell.className = " fc-state-disabled";
13721 if(ddMatch && format){
13722 var fvalue = d.dateFormat(format);
13723 if(ddMatch.test(fvalue)){
13724 cell.title = ddText.replace("%0", fvalue);
13725 cell.className = " fc-state-disabled";
13729 if (!cell.initialClassName) {
13730 cell.initialClassName = cell.dom.className;
13733 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13738 for(; i < startingPos; i++) {
13739 textEls[i].innerHTML = (++prevStart);
13740 d.setDate(d.getDate()+1);
13742 cells[i].className = "fc-past fc-other-month";
13743 setCellClass(this, cells[i]);
13748 for(; i < days; i++){
13749 intDay = i - startingPos + 1;
13750 textEls[i].innerHTML = (intDay);
13751 d.setDate(d.getDate()+1);
13753 cells[i].className = ''; // "x-date-active";
13754 setCellClass(this, cells[i]);
13758 for(; i < 42; i++) {
13759 textEls[i].innerHTML = (++extraDays);
13760 d.setDate(d.getDate()+1);
13762 cells[i].className = "fc-future fc-other-month";
13763 setCellClass(this, cells[i]);
13766 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13768 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13770 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13771 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13773 if(totalRows != 6){
13774 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13775 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13778 this.fireEvent('monthchange', this, date);
13782 if(!this.internalRender){
13783 var main = this.el.dom.firstChild;
13784 var w = main.offsetWidth;
13785 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13786 Roo.fly(main).setWidth(w);
13787 this.internalRender = true;
13788 // opera does not respect the auto grow header center column
13789 // then, after it gets a width opera refuses to recalculate
13790 // without a second pass
13791 if(Roo.isOpera && !this.secondPass){
13792 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13793 this.secondPass = true;
13794 this.update.defer(10, this, [date]);
13801 findCell : function(dt) {
13802 dt = dt.clearTime().getTime();
13804 this.cells.each(function(c){
13805 //Roo.log("check " +c.dateValue + '?=' + dt);
13806 if(c.dateValue == dt){
13816 findCells : function(ev) {
13817 var s = ev.start.clone().clearTime().getTime();
13819 var e= ev.end.clone().clearTime().getTime();
13822 this.cells.each(function(c){
13823 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13825 if(c.dateValue > e){
13828 if(c.dateValue < s){
13837 // findBestRow: function(cells)
13841 // for (var i =0 ; i < cells.length;i++) {
13842 // ret = Math.max(cells[i].rows || 0,ret);
13849 addItem : function(ev)
13851 // look for vertical location slot in
13852 var cells = this.findCells(ev);
13854 // ev.row = this.findBestRow(cells);
13856 // work out the location.
13860 for(var i =0; i < cells.length; i++) {
13862 cells[i].row = cells[0].row;
13865 cells[i].row = cells[i].row + 1;
13875 if (crow.start.getY() == cells[i].getY()) {
13877 crow.end = cells[i];
13894 cells[0].events.push(ev);
13896 this.calevents.push(ev);
13899 clearEvents: function() {
13901 if(!this.calevents){
13905 Roo.each(this.cells.elements, function(c){
13911 Roo.each(this.calevents, function(e) {
13912 Roo.each(e.els, function(el) {
13913 el.un('mouseenter' ,this.onEventEnter, this);
13914 el.un('mouseleave' ,this.onEventLeave, this);
13919 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13925 renderEvents: function()
13929 this.cells.each(function(c) {
13938 if(c.row != c.events.length){
13939 r = 4 - (4 - (c.row - c.events.length));
13942 c.events = ev.slice(0, r);
13943 c.more = ev.slice(r);
13945 if(c.more.length && c.more.length == 1){
13946 c.events.push(c.more.pop());
13949 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13953 this.cells.each(function(c) {
13955 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13958 for (var e = 0; e < c.events.length; e++){
13959 var ev = c.events[e];
13960 var rows = ev.rows;
13962 for(var i = 0; i < rows.length; i++) {
13964 // how many rows should it span..
13967 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13968 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13970 unselectable : "on",
13973 cls: 'fc-event-inner',
13977 // cls: 'fc-event-time',
13978 // html : cells.length > 1 ? '' : ev.time
13982 cls: 'fc-event-title',
13983 html : String.format('{0}', ev.title)
13990 cls: 'ui-resizable-handle ui-resizable-e',
13991 html : '  '
13998 cfg.cls += ' fc-event-start';
14000 if ((i+1) == rows.length) {
14001 cfg.cls += ' fc-event-end';
14004 var ctr = _this.el.select('.fc-event-container',true).first();
14005 var cg = ctr.createChild(cfg);
14007 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14008 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14010 var r = (c.more.length) ? 1 : 0;
14011 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14012 cg.setWidth(ebox.right - sbox.x -2);
14014 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14015 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14016 cg.on('click', _this.onEventClick, _this, ev);
14027 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14028 style : 'position: absolute',
14029 unselectable : "on",
14032 cls: 'fc-event-inner',
14036 cls: 'fc-event-title',
14044 cls: 'ui-resizable-handle ui-resizable-e',
14045 html : '  '
14051 var ctr = _this.el.select('.fc-event-container',true).first();
14052 var cg = ctr.createChild(cfg);
14054 var sbox = c.select('.fc-day-content',true).first().getBox();
14055 var ebox = c.select('.fc-day-content',true).first().getBox();
14057 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14058 cg.setWidth(ebox.right - sbox.x -2);
14060 cg.on('click', _this.onMoreEventClick, _this, c.more);
14070 onEventEnter: function (e, el,event,d) {
14071 this.fireEvent('evententer', this, el, event);
14074 onEventLeave: function (e, el,event,d) {
14075 this.fireEvent('eventleave', this, el, event);
14078 onEventClick: function (e, el,event,d) {
14079 this.fireEvent('eventclick', this, el, event);
14082 onMonthChange: function () {
14086 onMoreEventClick: function(e, el, more)
14090 this.calpopover.placement = 'right';
14091 this.calpopover.setTitle('More');
14093 this.calpopover.setContent('');
14095 var ctr = this.calpopover.el.select('.popover-content', true).first();
14097 Roo.each(more, function(m){
14099 cls : 'fc-event-hori fc-event-draggable',
14102 var cg = ctr.createChild(cfg);
14104 cg.on('click', _this.onEventClick, _this, m);
14107 this.calpopover.show(el);
14112 onLoad: function ()
14114 this.calevents = [];
14117 if(this.store.getCount() > 0){
14118 this.store.data.each(function(d){
14121 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14122 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14123 time : d.data.start_time,
14124 title : d.data.title,
14125 description : d.data.description,
14126 venue : d.data.venue
14131 this.renderEvents();
14133 if(this.calevents.length && this.loadMask){
14134 this.maskEl.hide();
14138 onBeforeLoad: function()
14140 this.clearEvents();
14142 this.maskEl.show();
14156 * @class Roo.bootstrap.Popover
14157 * @extends Roo.bootstrap.Component
14158 * Bootstrap Popover class
14159 * @cfg {String} html contents of the popover (or false to use children..)
14160 * @cfg {String} title of popover (or false to hide)
14161 * @cfg {String} placement how it is placed
14162 * @cfg {String} trigger click || hover (or false to trigger manually)
14163 * @cfg {String} over what (parent or false to trigger manually.)
14164 * @cfg {Number} delay - delay before showing
14167 * Create a new Popover
14168 * @param {Object} config The config object
14171 Roo.bootstrap.Popover = function(config){
14172 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14175 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14177 title: 'Fill in a title',
14180 placement : 'right',
14181 trigger : 'hover', // hover
14187 can_build_overlaid : false,
14189 getChildContainer : function()
14191 return this.el.select('.popover-content',true).first();
14194 getAutoCreate : function(){
14195 Roo.log('make popover?');
14197 cls : 'popover roo-dynamic',
14198 style: 'display:block',
14204 cls : 'popover-inner',
14208 cls: 'popover-title',
14212 cls : 'popover-content',
14223 setTitle: function(str)
14225 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14227 setContent: function(str)
14229 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14231 // as it get's added to the bottom of the page.
14232 onRender : function(ct, position)
14234 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14236 var cfg = Roo.apply({}, this.getAutoCreate());
14240 cfg.cls += ' ' + this.cls;
14243 cfg.style = this.style;
14245 Roo.log("adding to ")
14246 this.el = Roo.get(document.body).createChild(cfg, position);
14252 initEvents : function()
14254 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14255 this.el.enableDisplayMode('block');
14257 if (this.over === false) {
14260 if (this.triggers === false) {
14263 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14264 var triggers = this.trigger ? this.trigger.split(' ') : [];
14265 Roo.each(triggers, function(trigger) {
14267 if (trigger == 'click') {
14268 on_el.on('click', this.toggle, this);
14269 } else if (trigger != 'manual') {
14270 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14271 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14273 on_el.on(eventIn ,this.enter, this);
14274 on_el.on(eventOut, this.leave, this);
14285 toggle : function () {
14286 this.hoverState == 'in' ? this.leave() : this.enter();
14289 enter : function () {
14292 clearTimeout(this.timeout);
14294 this.hoverState = 'in';
14296 if (!this.delay || !this.delay.show) {
14301 this.timeout = setTimeout(function () {
14302 if (_t.hoverState == 'in') {
14305 }, this.delay.show)
14307 leave : function() {
14308 clearTimeout(this.timeout);
14310 this.hoverState = 'out';
14312 if (!this.delay || !this.delay.hide) {
14317 this.timeout = setTimeout(function () {
14318 if (_t.hoverState == 'out') {
14321 }, this.delay.hide)
14324 show : function (on_el)
14327 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14330 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14331 if (this.html !== false) {
14332 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14334 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14335 if (!this.title.length) {
14336 this.el.select('.popover-title',true).hide();
14339 var placement = typeof this.placement == 'function' ?
14340 this.placement.call(this, this.el, on_el) :
14343 var autoToken = /\s?auto?\s?/i;
14344 var autoPlace = autoToken.test(placement);
14346 placement = placement.replace(autoToken, '') || 'top';
14350 //this.el.setXY([0,0]);
14352 this.el.dom.style.display='block';
14353 this.el.addClass(placement);
14355 //this.el.appendTo(on_el);
14357 var p = this.getPosition();
14358 var box = this.el.getBox();
14363 var align = Roo.bootstrap.Popover.alignment[placement];
14364 this.el.alignTo(on_el, align[0],align[1]);
14365 //var arrow = this.el.select('.arrow',true).first();
14366 //arrow.set(align[2],
14368 this.el.addClass('in');
14369 this.hoverState = null;
14371 if (this.el.hasClass('fade')) {
14378 this.el.setXY([0,0]);
14379 this.el.removeClass('in');
14386 Roo.bootstrap.Popover.alignment = {
14387 'left' : ['r-l', [-10,0], 'right'],
14388 'right' : ['l-r', [10,0], 'left'],
14389 'bottom' : ['t-b', [0,10], 'top'],
14390 'top' : [ 'b-t', [0,-10], 'bottom']
14401 * @class Roo.bootstrap.Progress
14402 * @extends Roo.bootstrap.Component
14403 * Bootstrap Progress class
14404 * @cfg {Boolean} striped striped of the progress bar
14405 * @cfg {Boolean} active animated of the progress bar
14409 * Create a new Progress
14410 * @param {Object} config The config object
14413 Roo.bootstrap.Progress = function(config){
14414 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14417 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14422 getAutoCreate : function(){
14430 cfg.cls += ' progress-striped';
14434 cfg.cls += ' active';
14453 * @class Roo.bootstrap.ProgressBar
14454 * @extends Roo.bootstrap.Component
14455 * Bootstrap ProgressBar class
14456 * @cfg {Number} aria_valuenow aria-value now
14457 * @cfg {Number} aria_valuemin aria-value min
14458 * @cfg {Number} aria_valuemax aria-value max
14459 * @cfg {String} label label for the progress bar
14460 * @cfg {String} panel (success | info | warning | danger )
14461 * @cfg {String} role role of the progress bar
14462 * @cfg {String} sr_only text
14466 * Create a new ProgressBar
14467 * @param {Object} config The config object
14470 Roo.bootstrap.ProgressBar = function(config){
14471 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14474 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14478 aria_valuemax : 100,
14484 getAutoCreate : function()
14489 cls: 'progress-bar',
14490 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14502 cfg.role = this.role;
14505 if(this.aria_valuenow){
14506 cfg['aria-valuenow'] = this.aria_valuenow;
14509 if(this.aria_valuemin){
14510 cfg['aria-valuemin'] = this.aria_valuemin;
14513 if(this.aria_valuemax){
14514 cfg['aria-valuemax'] = this.aria_valuemax;
14517 if(this.label && !this.sr_only){
14518 cfg.html = this.label;
14522 cfg.cls += ' progress-bar-' + this.panel;
14528 update : function(aria_valuenow)
14530 this.aria_valuenow = aria_valuenow;
14532 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14547 * @class Roo.bootstrap.TabGroup
14548 * @extends Roo.bootstrap.Column
14549 * Bootstrap Column class
14550 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14551 * @cfg {Boolean} carousel true to make the group behave like a carousel
14552 * @cfg {Number} bullets show the panel pointer.. default 0
14553 * @cfg {Boolena} autoslide (true|false) auto slide .. default false
14554 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14557 * Create a new TabGroup
14558 * @param {Object} config The config object
14561 Roo.bootstrap.TabGroup = function(config){
14562 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14564 this.navId = Roo.id();
14567 Roo.bootstrap.TabGroup.register(this);
14571 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14574 transition : false,
14580 getAutoCreate : function()
14582 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14584 cfg.cls += ' tab-content';
14586 if (this.carousel) {
14587 cfg.cls += ' carousel slide';
14590 cls : 'carousel-inner'
14593 if(this.bullets > 0){
14596 cls : 'carousel-bullets',
14600 for (var i = 0; i < this.bullets; i++){
14602 cls : 'bullet bullet-' + i
14610 cfg.cn[0].cn = bullets;
14617 initEvents: function()
14619 Roo.log('-------- init events on tab group ---------');
14623 if(this.bullets > 0){
14625 for (var i = 0; i < this.bullets; i++){
14626 var bullet = this.el.select('.bullet-' + i, true).first();
14632 bullet.on('click', (function(e, el, o, ii, t){
14634 e.preventDefault();
14636 _this.showPanel(ii);
14638 }).createDelegate(this, [i, bullet], true));
14643 if(this.autoslide){
14644 this.slideFn = window.setInterval(function() {
14645 _this.showPanelNext();
14650 getChildContainer : function()
14652 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14656 * register a Navigation item
14657 * @param {Roo.bootstrap.NavItem} the navitem to add
14659 register : function(item)
14661 this.tabs.push( item);
14662 item.navId = this.navId; // not really needed..
14666 getActivePanel : function()
14669 Roo.each(this.tabs, function(t) {
14679 getPanelByName : function(n)
14682 Roo.each(this.tabs, function(t) {
14683 if (t.tabId == n) {
14691 indexOfPanel : function(p)
14694 Roo.each(this.tabs, function(t,i) {
14695 if (t.tabId == p.tabId) {
14704 * show a specific panel
14705 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14706 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14708 showPanel : function (pan)
14710 if(this.transition){
14711 Roo.log("waiting for the transitionend");
14715 if (typeof(pan) == 'number') {
14716 pan = this.tabs[pan];
14718 if (typeof(pan) == 'string') {
14719 pan = this.getPanelByName(pan);
14721 if (pan.tabId == this.getActivePanel().tabId) {
14724 var cur = this.getActivePanel();
14726 if (false === cur.fireEvent('beforedeactivate')) {
14730 if(this.bullets > 0){
14731 this.setActiveBullet(this.indexOfPanel(pan));
14734 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14736 this.transition = true;
14737 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14738 var lr = dir == 'next' ? 'left' : 'right';
14739 pan.el.addClass(dir); // or prev
14740 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14741 cur.el.addClass(lr); // or right
14742 pan.el.addClass(lr);
14745 cur.el.on('transitionend', function() {
14746 Roo.log("trans end?");
14748 pan.el.removeClass([lr,dir]);
14749 pan.setActive(true);
14751 cur.el.removeClass([lr]);
14752 cur.setActive(false);
14754 _this.transition = false;
14756 }, this, { single: true } );
14761 cur.setActive(false);
14762 pan.setActive(true);
14767 showPanelNext : function()
14769 var i = this.indexOfPanel(this.getActivePanel());
14771 if (i >= this.tabs.length - 1 && !this.autoslide) {
14775 if (i >= this.tabs.length - 1 && this.autoslide) {
14779 this.showPanel(this.tabs[i+1]);
14782 showPanelPrev : function()
14784 var i = this.indexOfPanel(this.getActivePanel());
14786 if (i < 1 && !this.autoslide) {
14790 if (i < 1 && this.autoslide) {
14791 i = this.tabs.length;
14794 this.showPanel(this.tabs[i-1]);
14797 setActiveBullet : function(i)
14799 Roo.each(this.el.select('.bullet', true).elements, function(el){
14800 el.removeClass('selected');
14803 var bullet = this.el.select('.bullet-' + i, true).first();
14809 bullet.addClass('selected');
14820 Roo.apply(Roo.bootstrap.TabGroup, {
14824 * register a Navigation Group
14825 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14827 register : function(navgrp)
14829 this.groups[navgrp.navId] = navgrp;
14833 * fetch a Navigation Group based on the navigation ID
14834 * if one does not exist , it will get created.
14835 * @param {string} the navgroup to add
14836 * @returns {Roo.bootstrap.NavGroup} the navgroup
14838 get: function(navId) {
14839 if (typeof(this.groups[navId]) == 'undefined') {
14840 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14842 return this.groups[navId] ;
14857 * @class Roo.bootstrap.TabPanel
14858 * @extends Roo.bootstrap.Component
14859 * Bootstrap TabPanel class
14860 * @cfg {Boolean} active panel active
14861 * @cfg {String} html panel content
14862 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14863 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14867 * Create a new TabPanel
14868 * @param {Object} config The config object
14871 Roo.bootstrap.TabPanel = function(config){
14872 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14876 * Fires when the active status changes
14877 * @param {Roo.bootstrap.TabPanel} this
14878 * @param {Boolean} state the new state
14883 * @event beforedeactivate
14884 * Fires before a tab is de-activated - can be used to do validation on a form.
14885 * @param {Roo.bootstrap.TabPanel} this
14886 * @return {Boolean} false if there is an error
14889 'beforedeactivate': true
14892 this.tabId = this.tabId || Roo.id();
14896 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14903 getAutoCreate : function(){
14906 // item is needed for carousel - not sure if it has any effect otherwise
14907 cls: 'tab-pane item',
14908 html: this.html || ''
14912 cfg.cls += ' active';
14916 cfg.tabId = this.tabId;
14923 initEvents: function()
14925 Roo.log('-------- init events on tab panel ---------');
14927 var p = this.parent();
14928 this.navId = this.navId || p.navId;
14930 if (typeof(this.navId) != 'undefined') {
14931 // not really needed.. but just in case.. parent should be a NavGroup.
14932 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14933 Roo.log(['register', tg, this]);
14936 var i = tg.tabs.length - 1;
14938 if(this.active && tg.bullets > 0 && i < tg.bullets){
14939 tg.setActiveBullet(i);
14946 onRender : function(ct, position)
14948 // Roo.log("Call onRender: " + this.xtype);
14950 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14958 setActive: function(state)
14960 Roo.log("panel - set active " + this.tabId + "=" + state);
14962 this.active = state;
14964 this.el.removeClass('active');
14966 } else if (!this.el.hasClass('active')) {
14967 this.el.addClass('active');
14970 this.fireEvent('changed', this, state);
14987 * @class Roo.bootstrap.DateField
14988 * @extends Roo.bootstrap.Input
14989 * Bootstrap DateField class
14990 * @cfg {Number} weekStart default 0
14991 * @cfg {String} viewMode default empty, (months|years)
14992 * @cfg {String} minViewMode default empty, (months|years)
14993 * @cfg {Number} startDate default -Infinity
14994 * @cfg {Number} endDate default Infinity
14995 * @cfg {Boolean} todayHighlight default false
14996 * @cfg {Boolean} todayBtn default false
14997 * @cfg {Boolean} calendarWeeks default false
14998 * @cfg {Object} daysOfWeekDisabled default empty
14999 * @cfg {Boolean} singleMode default false (true | false)
15001 * @cfg {Boolean} keyboardNavigation default true
15002 * @cfg {String} language default en
15005 * Create a new DateField
15006 * @param {Object} config The config object
15009 Roo.bootstrap.DateField = function(config){
15010 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15014 * Fires when this field show.
15015 * @param {Roo.bootstrap.DateField} this
15016 * @param {Mixed} date The date value
15021 * Fires when this field hide.
15022 * @param {Roo.bootstrap.DateField} this
15023 * @param {Mixed} date The date value
15028 * Fires when select a date.
15029 * @param {Roo.bootstrap.DateField} this
15030 * @param {Mixed} date The date value
15036 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15039 * @cfg {String} format
15040 * The default date format string which can be overriden for localization support. The format must be
15041 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15045 * @cfg {String} altFormats
15046 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15047 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15049 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15057 todayHighlight : false,
15063 keyboardNavigation: true,
15065 calendarWeeks: false,
15067 startDate: -Infinity,
15071 daysOfWeekDisabled: [],
15075 singleMode : false,
15077 UTCDate: function()
15079 return new Date(Date.UTC.apply(Date, arguments));
15082 UTCToday: function()
15084 var today = new Date();
15085 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15088 getDate: function() {
15089 var d = this.getUTCDate();
15090 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15093 getUTCDate: function() {
15097 setDate: function(d) {
15098 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15101 setUTCDate: function(d) {
15103 this.setValue(this.formatDate(this.date));
15106 onRender: function(ct, position)
15109 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15111 this.language = this.language || 'en';
15112 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15113 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15115 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15116 this.format = this.format || 'm/d/y';
15117 this.isInline = false;
15118 this.isInput = true;
15119 this.component = this.el.select('.add-on', true).first() || false;
15120 this.component = (this.component && this.component.length === 0) ? false : this.component;
15121 this.hasInput = this.component && this.inputEL().length;
15123 if (typeof(this.minViewMode === 'string')) {
15124 switch (this.minViewMode) {
15126 this.minViewMode = 1;
15129 this.minViewMode = 2;
15132 this.minViewMode = 0;
15137 if (typeof(this.viewMode === 'string')) {
15138 switch (this.viewMode) {
15151 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15153 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15155 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15157 this.picker().on('mousedown', this.onMousedown, this);
15158 this.picker().on('click', this.onClick, this);
15160 this.picker().addClass('datepicker-dropdown');
15162 this.startViewMode = this.viewMode;
15164 if(this.singleMode){
15165 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15166 v.setVisibilityMode(Roo.Element.DISPLAY)
15170 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15171 v.setStyle('width', '189px');
15175 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15176 if(!this.calendarWeeks){
15181 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15182 v.attr('colspan', function(i, val){
15183 return parseInt(val) + 1;
15188 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15190 this.setStartDate(this.startDate);
15191 this.setEndDate(this.endDate);
15193 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15200 if(this.isInline) {
15205 picker : function()
15207 return this.pickerEl;
15208 // return this.el.select('.datepicker', true).first();
15211 fillDow: function()
15213 var dowCnt = this.weekStart;
15222 if(this.calendarWeeks){
15230 while (dowCnt < this.weekStart + 7) {
15234 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15238 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15241 fillMonths: function()
15244 var months = this.picker().select('>.datepicker-months td', true).first();
15246 months.dom.innerHTML = '';
15252 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15255 months.createChild(month);
15262 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;
15264 if (this.date < this.startDate) {
15265 this.viewDate = new Date(this.startDate);
15266 } else if (this.date > this.endDate) {
15267 this.viewDate = new Date(this.endDate);
15269 this.viewDate = new Date(this.date);
15277 var d = new Date(this.viewDate),
15278 year = d.getUTCFullYear(),
15279 month = d.getUTCMonth(),
15280 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15281 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15282 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15283 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15284 currentDate = this.date && this.date.valueOf(),
15285 today = this.UTCToday();
15287 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15289 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15291 // this.picker.select('>tfoot th.today').
15292 // .text(dates[this.language].today)
15293 // .toggle(this.todayBtn !== false);
15295 this.updateNavArrows();
15298 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15300 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15302 prevMonth.setUTCDate(day);
15304 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15306 var nextMonth = new Date(prevMonth);
15308 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15310 nextMonth = nextMonth.valueOf();
15312 var fillMonths = false;
15314 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15316 while(prevMonth.valueOf() < nextMonth) {
15319 if (prevMonth.getUTCDay() === this.weekStart) {
15321 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15329 if(this.calendarWeeks){
15330 // ISO 8601: First week contains first thursday.
15331 // ISO also states week starts on Monday, but we can be more abstract here.
15333 // Start of current week: based on weekstart/current date
15334 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15335 // Thursday of this week
15336 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15337 // First Thursday of year, year from thursday
15338 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15339 // Calendar week: ms between thursdays, div ms per day, div 7 days
15340 calWeek = (th - yth) / 864e5 / 7 + 1;
15342 fillMonths.cn.push({
15350 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15352 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15355 if (this.todayHighlight &&
15356 prevMonth.getUTCFullYear() == today.getFullYear() &&
15357 prevMonth.getUTCMonth() == today.getMonth() &&
15358 prevMonth.getUTCDate() == today.getDate()) {
15359 clsName += ' today';
15362 if (currentDate && prevMonth.valueOf() === currentDate) {
15363 clsName += ' active';
15366 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15367 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15368 clsName += ' disabled';
15371 fillMonths.cn.push({
15373 cls: 'day ' + clsName,
15374 html: prevMonth.getDate()
15377 prevMonth.setDate(prevMonth.getDate()+1);
15380 var currentYear = this.date && this.date.getUTCFullYear();
15381 var currentMonth = this.date && this.date.getUTCMonth();
15383 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15385 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15386 v.removeClass('active');
15388 if(currentYear === year && k === currentMonth){
15389 v.addClass('active');
15392 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15393 v.addClass('disabled');
15399 year = parseInt(year/10, 10) * 10;
15401 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15403 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15406 for (var i = -1; i < 11; i++) {
15407 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15409 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15417 showMode: function(dir)
15420 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15423 Roo.each(this.picker().select('>div',true).elements, function(v){
15424 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15427 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15432 if(this.isInline) return;
15434 this.picker().removeClass(['bottom', 'top']);
15436 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15438 * place to the top of element!
15442 this.picker().addClass('top');
15443 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15448 this.picker().addClass('bottom');
15450 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15453 parseDate : function(value)
15455 if(!value || value instanceof Date){
15458 var v = Date.parseDate(value, this.format);
15459 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15460 v = Date.parseDate(value, 'Y-m-d');
15462 if(!v && this.altFormats){
15463 if(!this.altFormatsArray){
15464 this.altFormatsArray = this.altFormats.split("|");
15466 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15467 v = Date.parseDate(value, this.altFormatsArray[i]);
15473 formatDate : function(date, fmt)
15475 return (!date || !(date instanceof Date)) ?
15476 date : date.dateFormat(fmt || this.format);
15479 onFocus : function()
15481 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15485 onBlur : function()
15487 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15489 var d = this.inputEl().getValue();
15498 this.picker().show();
15502 this.fireEvent('show', this, this.date);
15507 if(this.isInline) return;
15508 this.picker().hide();
15509 this.viewMode = this.startViewMode;
15512 this.fireEvent('hide', this, this.date);
15516 onMousedown: function(e)
15518 e.stopPropagation();
15519 e.preventDefault();
15524 Roo.bootstrap.DateField.superclass.keyup.call(this);
15528 setValue: function(v)
15531 // v can be a string or a date..
15534 var d = new Date(this.parseDate(v) ).clearTime();
15536 if(isNaN(d.getTime())){
15537 this.date = this.viewDate = '';
15538 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15542 v = this.formatDate(d);
15544 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15546 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15550 this.fireEvent('select', this, this.date);
15554 getValue: function()
15556 return this.formatDate(this.date);
15559 fireKey: function(e)
15561 if (!this.picker().isVisible()){
15562 if (e.keyCode == 27) // allow escape to hide and re-show picker
15567 var dateChanged = false,
15569 newDate, newViewDate;
15574 e.preventDefault();
15578 if (!this.keyboardNavigation) break;
15579 dir = e.keyCode == 37 ? -1 : 1;
15582 newDate = this.moveYear(this.date, dir);
15583 newViewDate = this.moveYear(this.viewDate, dir);
15584 } else if (e.shiftKey){
15585 newDate = this.moveMonth(this.date, dir);
15586 newViewDate = this.moveMonth(this.viewDate, dir);
15588 newDate = new Date(this.date);
15589 newDate.setUTCDate(this.date.getUTCDate() + dir);
15590 newViewDate = new Date(this.viewDate);
15591 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15593 if (this.dateWithinRange(newDate)){
15594 this.date = newDate;
15595 this.viewDate = newViewDate;
15596 this.setValue(this.formatDate(this.date));
15598 e.preventDefault();
15599 dateChanged = true;
15604 if (!this.keyboardNavigation) break;
15605 dir = e.keyCode == 38 ? -1 : 1;
15607 newDate = this.moveYear(this.date, dir);
15608 newViewDate = this.moveYear(this.viewDate, dir);
15609 } else if (e.shiftKey){
15610 newDate = this.moveMonth(this.date, dir);
15611 newViewDate = this.moveMonth(this.viewDate, dir);
15613 newDate = new Date(this.date);
15614 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15615 newViewDate = new Date(this.viewDate);
15616 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15618 if (this.dateWithinRange(newDate)){
15619 this.date = newDate;
15620 this.viewDate = newViewDate;
15621 this.setValue(this.formatDate(this.date));
15623 e.preventDefault();
15624 dateChanged = true;
15628 this.setValue(this.formatDate(this.date));
15630 e.preventDefault();
15633 this.setValue(this.formatDate(this.date));
15647 onClick: function(e)
15649 e.stopPropagation();
15650 e.preventDefault();
15652 var target = e.getTarget();
15654 if(target.nodeName.toLowerCase() === 'i'){
15655 target = Roo.get(target).dom.parentNode;
15658 var nodeName = target.nodeName;
15659 var className = target.className;
15660 var html = target.innerHTML;
15661 //Roo.log(nodeName);
15663 switch(nodeName.toLowerCase()) {
15665 switch(className) {
15671 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15672 switch(this.viewMode){
15674 this.viewDate = this.moveMonth(this.viewDate, dir);
15678 this.viewDate = this.moveYear(this.viewDate, dir);
15684 var date = new Date();
15685 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15687 this.setValue(this.formatDate(this.date));
15694 if (className.indexOf('disabled') < 0) {
15695 this.viewDate.setUTCDate(1);
15696 if (className.indexOf('month') > -1) {
15697 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15699 var year = parseInt(html, 10) || 0;
15700 this.viewDate.setUTCFullYear(year);
15704 if(this.singleMode){
15705 this.setValue(this.formatDate(this.viewDate));
15716 //Roo.log(className);
15717 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15718 var day = parseInt(html, 10) || 1;
15719 var year = this.viewDate.getUTCFullYear(),
15720 month = this.viewDate.getUTCMonth();
15722 if (className.indexOf('old') > -1) {
15729 } else if (className.indexOf('new') > -1) {
15737 //Roo.log([year,month,day]);
15738 this.date = this.UTCDate(year, month, day,0,0,0,0);
15739 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15741 //Roo.log(this.formatDate(this.date));
15742 this.setValue(this.formatDate(this.date));
15749 setStartDate: function(startDate)
15751 this.startDate = startDate || -Infinity;
15752 if (this.startDate !== -Infinity) {
15753 this.startDate = this.parseDate(this.startDate);
15756 this.updateNavArrows();
15759 setEndDate: function(endDate)
15761 this.endDate = endDate || Infinity;
15762 if (this.endDate !== Infinity) {
15763 this.endDate = this.parseDate(this.endDate);
15766 this.updateNavArrows();
15769 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15771 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15772 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15773 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15775 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15776 return parseInt(d, 10);
15779 this.updateNavArrows();
15782 updateNavArrows: function()
15784 if(this.singleMode){
15788 var d = new Date(this.viewDate),
15789 year = d.getUTCFullYear(),
15790 month = d.getUTCMonth();
15792 Roo.each(this.picker().select('.prev', true).elements, function(v){
15794 switch (this.viewMode) {
15797 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15803 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15810 Roo.each(this.picker().select('.next', true).elements, function(v){
15812 switch (this.viewMode) {
15815 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15821 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15829 moveMonth: function(date, dir)
15831 if (!dir) return date;
15832 var new_date = new Date(date.valueOf()),
15833 day = new_date.getUTCDate(),
15834 month = new_date.getUTCMonth(),
15835 mag = Math.abs(dir),
15837 dir = dir > 0 ? 1 : -1;
15840 // If going back one month, make sure month is not current month
15841 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15843 return new_date.getUTCMonth() == month;
15845 // If going forward one month, make sure month is as expected
15846 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15848 return new_date.getUTCMonth() != new_month;
15850 new_month = month + dir;
15851 new_date.setUTCMonth(new_month);
15852 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15853 if (new_month < 0 || new_month > 11)
15854 new_month = (new_month + 12) % 12;
15856 // For magnitudes >1, move one month at a time...
15857 for (var i=0; i<mag; i++)
15858 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15859 new_date = this.moveMonth(new_date, dir);
15860 // ...then reset the day, keeping it in the new month
15861 new_month = new_date.getUTCMonth();
15862 new_date.setUTCDate(day);
15864 return new_month != new_date.getUTCMonth();
15867 // Common date-resetting loop -- if date is beyond end of month, make it
15870 new_date.setUTCDate(--day);
15871 new_date.setUTCMonth(new_month);
15876 moveYear: function(date, dir)
15878 return this.moveMonth(date, dir*12);
15881 dateWithinRange: function(date)
15883 return date >= this.startDate && date <= this.endDate;
15889 this.picker().remove();
15894 Roo.apply(Roo.bootstrap.DateField, {
15905 html: '<i class="fa fa-arrow-left"/>'
15915 html: '<i class="fa fa-arrow-right"/>'
15957 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15958 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15959 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15960 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15961 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15974 navFnc: 'FullYear',
15979 navFnc: 'FullYear',
15984 Roo.apply(Roo.bootstrap.DateField, {
15988 cls: 'datepicker dropdown-menu roo-dynamic',
15992 cls: 'datepicker-days',
15996 cls: 'table-condensed',
15998 Roo.bootstrap.DateField.head,
16002 Roo.bootstrap.DateField.footer
16009 cls: 'datepicker-months',
16013 cls: 'table-condensed',
16015 Roo.bootstrap.DateField.head,
16016 Roo.bootstrap.DateField.content,
16017 Roo.bootstrap.DateField.footer
16024 cls: 'datepicker-years',
16028 cls: 'table-condensed',
16030 Roo.bootstrap.DateField.head,
16031 Roo.bootstrap.DateField.content,
16032 Roo.bootstrap.DateField.footer
16051 * @class Roo.bootstrap.TimeField
16052 * @extends Roo.bootstrap.Input
16053 * Bootstrap DateField class
16057 * Create a new TimeField
16058 * @param {Object} config The config object
16061 Roo.bootstrap.TimeField = function(config){
16062 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16066 * Fires when this field show.
16067 * @param {Roo.bootstrap.DateField} thisthis
16068 * @param {Mixed} date The date value
16073 * Fires when this field hide.
16074 * @param {Roo.bootstrap.DateField} this
16075 * @param {Mixed} date The date value
16080 * Fires when select a date.
16081 * @param {Roo.bootstrap.DateField} this
16082 * @param {Mixed} date The date value
16088 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16091 * @cfg {String} format
16092 * The default time format string which can be overriden for localization support. The format must be
16093 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16097 onRender: function(ct, position)
16100 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16102 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16104 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16106 this.pop = this.picker().select('>.datepicker-time',true).first();
16107 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16109 this.picker().on('mousedown', this.onMousedown, this);
16110 this.picker().on('click', this.onClick, this);
16112 this.picker().addClass('datepicker-dropdown');
16117 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16118 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16119 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16120 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16121 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16122 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16126 fireKey: function(e){
16127 if (!this.picker().isVisible()){
16128 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16134 e.preventDefault();
16142 this.onTogglePeriod();
16145 this.onIncrementMinutes();
16148 this.onDecrementMinutes();
16157 onClick: function(e) {
16158 e.stopPropagation();
16159 e.preventDefault();
16162 picker : function()
16164 return this.el.select('.datepicker', true).first();
16167 fillTime: function()
16169 var time = this.pop.select('tbody', true).first();
16171 time.dom.innerHTML = '';
16186 cls: 'hours-up glyphicon glyphicon-chevron-up'
16206 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16227 cls: 'timepicker-hour',
16242 cls: 'timepicker-minute',
16257 cls: 'btn btn-primary period',
16279 cls: 'hours-down glyphicon glyphicon-chevron-down'
16299 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16317 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16324 var hours = this.time.getHours();
16325 var minutes = this.time.getMinutes();
16338 hours = hours - 12;
16342 hours = '0' + hours;
16346 minutes = '0' + minutes;
16349 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16350 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16351 this.pop.select('button', true).first().dom.innerHTML = period;
16357 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16359 var cls = ['bottom'];
16361 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16368 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16373 this.picker().addClass(cls.join('-'));
16377 Roo.each(cls, function(c){
16379 _this.picker().setTop(_this.inputEl().getHeight());
16383 _this.picker().setTop(0 - _this.picker().getHeight());
16388 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16392 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16399 onFocus : function()
16401 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16405 onBlur : function()
16407 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16413 this.picker().show();
16418 this.fireEvent('show', this, this.date);
16423 this.picker().hide();
16426 this.fireEvent('hide', this, this.date);
16429 setTime : function()
16432 this.setValue(this.time.format(this.format));
16434 this.fireEvent('select', this, this.date);
16439 onMousedown: function(e){
16440 e.stopPropagation();
16441 e.preventDefault();
16444 onIncrementHours: function()
16446 Roo.log('onIncrementHours');
16447 this.time = this.time.add(Date.HOUR, 1);
16452 onDecrementHours: function()
16454 Roo.log('onDecrementHours');
16455 this.time = this.time.add(Date.HOUR, -1);
16459 onIncrementMinutes: function()
16461 Roo.log('onIncrementMinutes');
16462 this.time = this.time.add(Date.MINUTE, 1);
16466 onDecrementMinutes: function()
16468 Roo.log('onDecrementMinutes');
16469 this.time = this.time.add(Date.MINUTE, -1);
16473 onTogglePeriod: function()
16475 Roo.log('onTogglePeriod');
16476 this.time = this.time.add(Date.HOUR, 12);
16483 Roo.apply(Roo.bootstrap.TimeField, {
16513 cls: 'btn btn-info ok',
16525 Roo.apply(Roo.bootstrap.TimeField, {
16529 cls: 'datepicker dropdown-menu',
16533 cls: 'datepicker-time',
16537 cls: 'table-condensed',
16539 Roo.bootstrap.TimeField.content,
16540 Roo.bootstrap.TimeField.footer
16559 * @class Roo.bootstrap.MonthField
16560 * @extends Roo.bootstrap.Input
16561 * Bootstrap MonthField class
16563 * @cfg {String} language default en
16566 * Create a new MonthField
16567 * @param {Object} config The config object
16570 Roo.bootstrap.MonthField = function(config){
16571 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16576 * Fires when this field show.
16577 * @param {Roo.bootstrap.MonthField} this
16578 * @param {Mixed} date The date value
16583 * Fires when this field hide.
16584 * @param {Roo.bootstrap.MonthField} this
16585 * @param {Mixed} date The date value
16590 * Fires when select a date.
16591 * @param {Roo.bootstrap.MonthField} this
16592 * @param {String} oldvalue The old value
16593 * @param {String} newvalue The new value
16599 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16601 onRender: function(ct, position)
16604 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16606 this.language = this.language || 'en';
16607 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16608 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16610 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16611 this.isInline = false;
16612 this.isInput = true;
16613 this.component = this.el.select('.add-on', true).first() || false;
16614 this.component = (this.component && this.component.length === 0) ? false : this.component;
16615 this.hasInput = this.component && this.inputEL().length;
16617 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16619 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16621 this.picker().on('mousedown', this.onMousedown, this);
16622 this.picker().on('click', this.onClick, this);
16624 this.picker().addClass('datepicker-dropdown');
16626 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16627 v.setStyle('width', '189px');
16634 if(this.isInline) {
16640 setValue: function(v, suppressEvent)
16642 var o = this.getValue();
16644 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16648 if(suppressEvent !== true){
16649 this.fireEvent('select', this, o, v);
16654 getValue: function()
16659 onClick: function(e)
16661 e.stopPropagation();
16662 e.preventDefault();
16664 var target = e.getTarget();
16666 if(target.nodeName.toLowerCase() === 'i'){
16667 target = Roo.get(target).dom.parentNode;
16670 var nodeName = target.nodeName;
16671 var className = target.className;
16672 var html = target.innerHTML;
16674 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16678 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16680 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16686 picker : function()
16688 return this.pickerEl;
16691 fillMonths: function()
16694 var months = this.picker().select('>.datepicker-months td', true).first();
16696 months.dom.innerHTML = '';
16702 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16705 months.createChild(month);
16714 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16715 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16718 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16719 e.removeClass('active');
16721 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16722 e.addClass('active');
16729 if(this.isInline) return;
16731 this.picker().removeClass(['bottom', 'top']);
16733 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16735 * place to the top of element!
16739 this.picker().addClass('top');
16740 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16745 this.picker().addClass('bottom');
16747 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16750 onFocus : function()
16752 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16756 onBlur : function()
16758 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16760 var d = this.inputEl().getValue();
16769 this.picker().show();
16770 this.picker().select('>.datepicker-months', true).first().show();
16774 this.fireEvent('show', this, this.date);
16779 if(this.isInline) return;
16780 this.picker().hide();
16781 this.fireEvent('hide', this, this.date);
16785 onMousedown: function(e)
16787 e.stopPropagation();
16788 e.preventDefault();
16793 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16797 fireKey: function(e)
16799 if (!this.picker().isVisible()){
16800 if (e.keyCode == 27) // allow escape to hide and re-show picker
16810 e.preventDefault();
16814 dir = e.keyCode == 37 ? -1 : 1;
16816 this.vIndex = this.vIndex + dir;
16818 if(this.vIndex < 0){
16822 if(this.vIndex > 11){
16826 if(isNaN(this.vIndex)){
16830 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16836 dir = e.keyCode == 38 ? -1 : 1;
16838 this.vIndex = this.vIndex + dir * 4;
16840 if(this.vIndex < 0){
16844 if(this.vIndex > 11){
16848 if(isNaN(this.vIndex)){
16852 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16857 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16858 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16862 e.preventDefault();
16865 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16866 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16882 this.picker().remove();
16887 Roo.apply(Roo.bootstrap.MonthField, {
16906 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16907 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16912 Roo.apply(Roo.bootstrap.MonthField, {
16916 cls: 'datepicker dropdown-menu roo-dynamic',
16920 cls: 'datepicker-months',
16924 cls: 'table-condensed',
16926 Roo.bootstrap.DateField.content
16946 * @class Roo.bootstrap.CheckBox
16947 * @extends Roo.bootstrap.Input
16948 * Bootstrap CheckBox class
16950 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16951 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16952 * @cfg {String} boxLabel The text that appears beside the checkbox
16953 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16954 * @cfg {Boolean} checked initnal the element
16955 * @cfg {Boolean} inline inline the element (default false)
16956 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16959 * Create a new CheckBox
16960 * @param {Object} config The config object
16963 Roo.bootstrap.CheckBox = function(config){
16964 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16969 * Fires when the element is checked or unchecked.
16970 * @param {Roo.bootstrap.CheckBox} this This input
16971 * @param {Boolean} checked The new checked value
16978 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16980 inputType: 'checkbox',
16988 getAutoCreate : function()
16990 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16996 cfg.cls = 'form-group ' + this.inputType; //input-group
16999 cfg.cls += ' ' + this.inputType + '-inline';
17005 type : this.inputType,
17006 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17007 cls : 'roo-' + this.inputType, //'form-box',
17008 placeholder : this.placeholder || ''
17012 if (this.weight) { // Validity check?
17013 cfg.cls += " " + this.inputType + "-" + this.weight;
17016 if (this.disabled) {
17017 input.disabled=true;
17021 input.checked = this.checked;
17025 input.name = this.name;
17029 input.cls += ' input-' + this.size;
17034 ['xs','sm','md','lg'].map(function(size){
17035 if (settings[size]) {
17036 cfg.cls += ' col-' + size + '-' + settings[size];
17040 var inputblock = input;
17042 if (this.before || this.after) {
17045 cls : 'input-group',
17050 inputblock.cn.push({
17052 cls : 'input-group-addon',
17057 inputblock.cn.push(input);
17060 inputblock.cn.push({
17062 cls : 'input-group-addon',
17069 if (align ==='left' && this.fieldLabel.length) {
17070 Roo.log("left and has label");
17076 cls : 'control-label col-md-' + this.labelWidth,
17077 html : this.fieldLabel
17081 cls : "col-md-" + (12 - this.labelWidth),
17088 } else if ( this.fieldLabel.length) {
17093 tag: this.boxLabel ? 'span' : 'label',
17095 cls: 'control-label box-input-label',
17096 //cls : 'input-group-addon',
17097 html : this.fieldLabel
17107 Roo.log(" no label && no align");
17108 cfg.cn = [ inputblock ] ;
17113 var boxLabelCfg = {
17115 //'for': id, // box label is handled by onclick - so no for...
17117 html: this.boxLabel
17121 boxLabelCfg.tooltip = this.tooltip;
17124 cfg.cn.push(boxLabelCfg);
17134 * return the real input element.
17136 inputEl: function ()
17138 return this.el.select('input.roo-' + this.inputType,true).first();
17141 labelEl: function()
17143 return this.el.select('label.control-label',true).first();
17145 /* depricated... */
17149 return this.labelEl();
17152 initEvents : function()
17154 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17156 this.inputEl().on('click', this.onClick, this);
17158 if (this.boxLabel) {
17159 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17162 this.startValue = this.getValue();
17165 Roo.bootstrap.CheckBox.register(this);
17169 onClick : function()
17171 this.setChecked(!this.checked);
17174 setChecked : function(state,suppressEvent)
17176 this.startValue = this.getValue();
17178 if(this.inputType == 'radio'){
17180 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17181 e.dom.checked = false;
17184 this.inputEl().dom.checked = true;
17186 this.inputEl().dom.value = this.inputValue;
17188 if(suppressEvent !== true){
17189 this.fireEvent('check', this, true);
17197 this.checked = state;
17199 this.inputEl().dom.checked = state;
17201 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17203 if(suppressEvent !== true){
17204 this.fireEvent('check', this, state);
17210 getValue : function()
17212 if(this.inputType == 'radio'){
17213 return this.getGroupValue();
17216 return this.inputEl().getValue();
17220 getGroupValue : function()
17222 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17226 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17229 setValue : function(v,suppressEvent)
17231 if(this.inputType == 'radio'){
17232 this.setGroupValue(v, suppressEvent);
17236 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17241 setGroupValue : function(v, suppressEvent)
17243 this.startValue = this.getValue();
17245 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17246 e.dom.checked = false;
17248 if(e.dom.value == v){
17249 e.dom.checked = true;
17253 if(suppressEvent !== true){
17254 this.fireEvent('check', this, true);
17262 validate : function()
17266 (this.inputType == 'radio' && this.validateRadio()) ||
17267 (this.inputType == 'checkbox' && this.validateCheckbox())
17273 this.markInvalid();
17277 validateRadio : function()
17281 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17282 if(!e.dom.checked){
17294 validateCheckbox : function()
17297 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17300 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17308 for(var i in group){
17313 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17320 * Mark this field as valid
17322 markValid : function()
17324 if(this.allowBlank){
17330 this.fireEvent('valid', this);
17332 if(this.inputType == 'radio'){
17333 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17334 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17335 e.findParent('.form-group', false, true).addClass(_this.validClass);
17342 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17343 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17347 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17353 for(var i in group){
17354 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17355 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17360 * Mark this field as invalid
17361 * @param {String} msg The validation message
17363 markInvalid : function(msg)
17365 if(this.allowBlank){
17371 this.fireEvent('invalid', this, msg);
17373 if(this.inputType == 'radio'){
17374 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17375 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17376 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17383 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17384 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17388 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17394 for(var i in group){
17395 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17396 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17403 Roo.apply(Roo.bootstrap.CheckBox, {
17408 * register a CheckBox Group
17409 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17411 register : function(checkbox)
17413 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17414 this.groups[checkbox.groupId] = {};
17417 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17421 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17425 * fetch a CheckBox Group based on the group ID
17426 * @param {string} the group ID
17427 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17429 get: function(groupId) {
17430 if (typeof(this.groups[groupId]) == 'undefined') {
17434 return this.groups[groupId] ;
17446 *<div class="radio">
17448 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17449 Option one is this and that—be sure to include why it's great
17456 *<label class="radio-inline">fieldLabel</label>
17457 *<label class="radio-inline">
17458 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17466 * @class Roo.bootstrap.Radio
17467 * @extends Roo.bootstrap.CheckBox
17468 * Bootstrap Radio class
17471 * Create a new Radio
17472 * @param {Object} config The config object
17475 Roo.bootstrap.Radio = function(config){
17476 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17480 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17482 inputType: 'radio',
17486 getAutoCreate : function()
17488 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17489 align = align || 'left'; // default...
17496 tag : this.inline ? 'span' : 'div',
17501 var inline = this.inline ? ' radio-inline' : '';
17505 // does not need for, as we wrap the input with it..
17507 cls : 'control-label box-label' + inline,
17510 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17514 //cls : 'control-label' + inline,
17515 html : this.fieldLabel,
17516 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17525 type : this.inputType,
17526 //value : (!this.checked) ? this.valueOff : this.inputValue,
17527 value : this.inputValue,
17529 placeholder : this.placeholder || '' // ?? needed????
17532 if (this.weight) { // Validity check?
17533 input.cls += " radio-" + this.weight;
17535 if (this.disabled) {
17536 input.disabled=true;
17540 input.checked = this.checked;
17544 input.name = this.name;
17548 input.cls += ' input-' + this.size;
17551 //?? can span's inline have a width??
17554 ['xs','sm','md','lg'].map(function(size){
17555 if (settings[size]) {
17556 cfg.cls += ' col-' + size + '-' + settings[size];
17560 var inputblock = input;
17562 if (this.before || this.after) {
17565 cls : 'input-group',
17570 inputblock.cn.push({
17572 cls : 'input-group-addon',
17576 inputblock.cn.push(input);
17578 inputblock.cn.push({
17580 cls : 'input-group-addon',
17588 if (this.fieldLabel && this.fieldLabel.length) {
17589 cfg.cn.push(fieldLabel);
17592 // normal bootstrap puts the input inside the label.
17593 // however with our styled version - it has to go after the input.
17595 //lbl.cn.push(inputblock);
17599 cls: 'radio' + inline,
17606 cfg.cn.push( lblwrap);
17611 html: this.boxLabel
17620 initEvents : function()
17622 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17624 this.inputEl().on('click', this.onClick, this);
17625 if (this.boxLabel) {
17626 Roo.log('find label')
17627 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17632 inputEl: function ()
17634 return this.el.select('input.roo-radio',true).first();
17636 onClick : function()
17639 this.setChecked(true);
17642 setChecked : function(state,suppressEvent)
17645 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17646 v.dom.checked = false;
17649 Roo.log(this.inputEl().dom);
17650 this.checked = state;
17651 this.inputEl().dom.checked = state;
17653 if(suppressEvent !== true){
17654 this.fireEvent('check', this, state);
17657 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17661 getGroupValue : function()
17664 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17665 if(v.dom.checked == true){
17666 value = v.dom.value;
17674 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17675 * @return {Mixed} value The field value
17677 getValue : function(){
17678 return this.getGroupValue();
17684 //<script type="text/javascript">
17687 * Based Ext JS Library 1.1.1
17688 * Copyright(c) 2006-2007, Ext JS, LLC.
17694 * @class Roo.HtmlEditorCore
17695 * @extends Roo.Component
17696 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17698 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17701 Roo.HtmlEditorCore = function(config){
17704 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17709 * @event initialize
17710 * Fires when the editor is fully initialized (including the iframe)
17711 * @param {Roo.HtmlEditorCore} this
17716 * Fires when the editor is first receives the focus. Any insertion must wait
17717 * until after this event.
17718 * @param {Roo.HtmlEditorCore} this
17722 * @event beforesync
17723 * Fires before the textarea is updated with content from the editor iframe. Return false
17724 * to cancel the sync.
17725 * @param {Roo.HtmlEditorCore} this
17726 * @param {String} html
17730 * @event beforepush
17731 * Fires before the iframe editor is updated with content from the textarea. Return false
17732 * to cancel the push.
17733 * @param {Roo.HtmlEditorCore} this
17734 * @param {String} html
17739 * Fires when the textarea is updated with content from the editor iframe.
17740 * @param {Roo.HtmlEditorCore} this
17741 * @param {String} html
17746 * Fires when the iframe editor is updated with content from the textarea.
17747 * @param {Roo.HtmlEditorCore} this
17748 * @param {String} html
17753 * @event editorevent
17754 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17755 * @param {Roo.HtmlEditorCore} this
17761 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17763 // defaults : white / black...
17764 this.applyBlacklists();
17771 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17775 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17781 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17786 * @cfg {Number} height (in pixels)
17790 * @cfg {Number} width (in pixels)
17795 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17798 stylesheets: false,
17803 // private properties
17804 validationEvent : false,
17806 initialized : false,
17808 sourceEditMode : false,
17809 onFocus : Roo.emptyFn,
17811 hideMode:'offsets',
17815 // blacklist + whitelisted elements..
17822 * Protected method that will not generally be called directly. It
17823 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17824 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17826 getDocMarkup : function(){
17830 // inherit styels from page...??
17831 if (this.stylesheets === false) {
17833 Roo.get(document.head).select('style').each(function(node) {
17834 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17837 Roo.get(document.head).select('link').each(function(node) {
17838 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17841 } else if (!this.stylesheets.length) {
17843 st = '<style type="text/css">' +
17844 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17850 st += '<style type="text/css">' +
17851 'IMG { cursor: pointer } ' +
17855 return '<html><head>' + st +
17856 //<style type="text/css">' +
17857 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17859 ' </head><body class="roo-htmleditor-body"></body></html>';
17863 onRender : function(ct, position)
17866 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17867 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17870 this.el.dom.style.border = '0 none';
17871 this.el.dom.setAttribute('tabIndex', -1);
17872 this.el.addClass('x-hidden hide');
17876 if(Roo.isIE){ // fix IE 1px bogus margin
17877 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17881 this.frameId = Roo.id();
17885 var iframe = this.owner.wrap.createChild({
17887 cls: 'form-control', // bootstrap..
17889 name: this.frameId,
17890 frameBorder : 'no',
17891 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17896 this.iframe = iframe.dom;
17898 this.assignDocWin();
17900 this.doc.designMode = 'on';
17903 this.doc.write(this.getDocMarkup());
17907 var task = { // must defer to wait for browser to be ready
17909 //console.log("run task?" + this.doc.readyState);
17910 this.assignDocWin();
17911 if(this.doc.body || this.doc.readyState == 'complete'){
17913 this.doc.designMode="on";
17917 Roo.TaskMgr.stop(task);
17918 this.initEditor.defer(10, this);
17925 Roo.TaskMgr.start(task);
17930 onResize : function(w, h)
17932 Roo.log('resize: ' +w + ',' + h );
17933 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17937 if(typeof w == 'number'){
17939 this.iframe.style.width = w + 'px';
17941 if(typeof h == 'number'){
17943 this.iframe.style.height = h + 'px';
17945 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17952 * Toggles the editor between standard and source edit mode.
17953 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17955 toggleSourceEdit : function(sourceEditMode){
17957 this.sourceEditMode = sourceEditMode === true;
17959 if(this.sourceEditMode){
17961 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17964 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17965 //this.iframe.className = '';
17968 //this.setSize(this.owner.wrap.getSize());
17969 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17976 * Protected method that will not generally be called directly. If you need/want
17977 * custom HTML cleanup, this is the method you should override.
17978 * @param {String} html The HTML to be cleaned
17979 * return {String} The cleaned HTML
17981 cleanHtml : function(html){
17982 html = String(html);
17983 if(html.length > 5){
17984 if(Roo.isSafari){ // strip safari nonsense
17985 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17988 if(html == ' '){
17995 * HTML Editor -> Textarea
17996 * Protected method that will not generally be called directly. Syncs the contents
17997 * of the editor iframe with the textarea.
17999 syncValue : function(){
18000 if(this.initialized){
18001 var bd = (this.doc.body || this.doc.documentElement);
18002 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18003 var html = bd.innerHTML;
18005 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18006 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18008 html = '<div style="'+m[0]+'">' + html + '</div>';
18011 html = this.cleanHtml(html);
18012 // fix up the special chars.. normaly like back quotes in word...
18013 // however we do not want to do this with chinese..
18014 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18015 var cc = b.charCodeAt();
18017 (cc >= 0x4E00 && cc < 0xA000 ) ||
18018 (cc >= 0x3400 && cc < 0x4E00 ) ||
18019 (cc >= 0xf900 && cc < 0xfb00 )
18025 if(this.owner.fireEvent('beforesync', this, html) !== false){
18026 this.el.dom.value = html;
18027 this.owner.fireEvent('sync', this, html);
18033 * Protected method that will not generally be called directly. Pushes the value of the textarea
18034 * into the iframe editor.
18036 pushValue : function(){
18037 if(this.initialized){
18038 var v = this.el.dom.value.trim();
18040 // if(v.length < 1){
18044 if(this.owner.fireEvent('beforepush', this, v) !== false){
18045 var d = (this.doc.body || this.doc.documentElement);
18047 this.cleanUpPaste();
18048 this.el.dom.value = d.innerHTML;
18049 this.owner.fireEvent('push', this, v);
18055 deferFocus : function(){
18056 this.focus.defer(10, this);
18060 focus : function(){
18061 if(this.win && !this.sourceEditMode){
18068 assignDocWin: function()
18070 var iframe = this.iframe;
18073 this.doc = iframe.contentWindow.document;
18074 this.win = iframe.contentWindow;
18076 // if (!Roo.get(this.frameId)) {
18079 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18080 // this.win = Roo.get(this.frameId).dom.contentWindow;
18082 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18086 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18087 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18092 initEditor : function(){
18093 //console.log("INIT EDITOR");
18094 this.assignDocWin();
18098 this.doc.designMode="on";
18100 this.doc.write(this.getDocMarkup());
18103 var dbody = (this.doc.body || this.doc.documentElement);
18104 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18105 // this copies styles from the containing element into thsi one..
18106 // not sure why we need all of this..
18107 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18109 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18110 //ss['background-attachment'] = 'fixed'; // w3c
18111 dbody.bgProperties = 'fixed'; // ie
18112 //Roo.DomHelper.applyStyles(dbody, ss);
18113 Roo.EventManager.on(this.doc, {
18114 //'mousedown': this.onEditorEvent,
18115 'mouseup': this.onEditorEvent,
18116 'dblclick': this.onEditorEvent,
18117 'click': this.onEditorEvent,
18118 'keyup': this.onEditorEvent,
18123 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18125 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18126 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18128 this.initialized = true;
18130 this.owner.fireEvent('initialize', this);
18135 onDestroy : function(){
18141 //for (var i =0; i < this.toolbars.length;i++) {
18142 // // fixme - ask toolbars for heights?
18143 // this.toolbars[i].onDestroy();
18146 //this.wrap.dom.innerHTML = '';
18147 //this.wrap.remove();
18152 onFirstFocus : function(){
18154 this.assignDocWin();
18157 this.activated = true;
18160 if(Roo.isGecko){ // prevent silly gecko errors
18162 var s = this.win.getSelection();
18163 if(!s.focusNode || s.focusNode.nodeType != 3){
18164 var r = s.getRangeAt(0);
18165 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18170 this.execCmd('useCSS', true);
18171 this.execCmd('styleWithCSS', false);
18174 this.owner.fireEvent('activate', this);
18178 adjustFont: function(btn){
18179 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18180 //if(Roo.isSafari){ // safari
18183 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18184 if(Roo.isSafari){ // safari
18185 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18186 v = (v < 10) ? 10 : v;
18187 v = (v > 48) ? 48 : v;
18188 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18193 v = Math.max(1, v+adjust);
18195 this.execCmd('FontSize', v );
18198 onEditorEvent : function(e){
18199 this.owner.fireEvent('editorevent', this, e);
18200 // this.updateToolbar();
18201 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18204 insertTag : function(tg)
18206 // could be a bit smarter... -> wrap the current selected tRoo..
18207 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18209 range = this.createRange(this.getSelection());
18210 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18211 wrappingNode.appendChild(range.extractContents());
18212 range.insertNode(wrappingNode);
18219 this.execCmd("formatblock", tg);
18223 insertText : function(txt)
18227 var range = this.createRange();
18228 range.deleteContents();
18229 //alert(Sender.getAttribute('label'));
18231 range.insertNode(this.doc.createTextNode(txt));
18237 * Executes a Midas editor command on the editor document and performs necessary focus and
18238 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18239 * @param {String} cmd The Midas command
18240 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18242 relayCmd : function(cmd, value){
18244 this.execCmd(cmd, value);
18245 this.owner.fireEvent('editorevent', this);
18246 //this.updateToolbar();
18247 this.owner.deferFocus();
18251 * Executes a Midas editor command directly on the editor document.
18252 * For visual commands, you should use {@link #relayCmd} instead.
18253 * <b>This should only be called after the editor is initialized.</b>
18254 * @param {String} cmd The Midas command
18255 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18257 execCmd : function(cmd, value){
18258 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18265 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18267 * @param {String} text | dom node..
18269 insertAtCursor : function(text)
18274 if(!this.activated){
18280 var r = this.doc.selection.createRange();
18291 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18295 // from jquery ui (MIT licenced)
18297 var win = this.win;
18299 if (win.getSelection && win.getSelection().getRangeAt) {
18300 range = win.getSelection().getRangeAt(0);
18301 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18302 range.insertNode(node);
18303 } else if (win.document.selection && win.document.selection.createRange) {
18304 // no firefox support
18305 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18306 win.document.selection.createRange().pasteHTML(txt);
18308 // no firefox support
18309 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18310 this.execCmd('InsertHTML', txt);
18319 mozKeyPress : function(e){
18321 var c = e.getCharCode(), cmd;
18324 c = String.fromCharCode(c).toLowerCase();
18338 this.cleanUpPaste.defer(100, this);
18346 e.preventDefault();
18354 fixKeys : function(){ // load time branching for fastest keydown performance
18356 return function(e){
18357 var k = e.getKey(), r;
18360 r = this.doc.selection.createRange();
18363 r.pasteHTML('    ');
18370 r = this.doc.selection.createRange();
18372 var target = r.parentElement();
18373 if(!target || target.tagName.toLowerCase() != 'li'){
18375 r.pasteHTML('<br />');
18381 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18382 this.cleanUpPaste.defer(100, this);
18388 }else if(Roo.isOpera){
18389 return function(e){
18390 var k = e.getKey();
18394 this.execCmd('InsertHTML','    ');
18397 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18398 this.cleanUpPaste.defer(100, this);
18403 }else if(Roo.isSafari){
18404 return function(e){
18405 var k = e.getKey();
18409 this.execCmd('InsertText','\t');
18413 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18414 this.cleanUpPaste.defer(100, this);
18422 getAllAncestors: function()
18424 var p = this.getSelectedNode();
18427 a.push(p); // push blank onto stack..
18428 p = this.getParentElement();
18432 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18436 a.push(this.doc.body);
18440 lastSelNode : false,
18443 getSelection : function()
18445 this.assignDocWin();
18446 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18449 getSelectedNode: function()
18451 // this may only work on Gecko!!!
18453 // should we cache this!!!!
18458 var range = this.createRange(this.getSelection()).cloneRange();
18461 var parent = range.parentElement();
18463 var testRange = range.duplicate();
18464 testRange.moveToElementText(parent);
18465 if (testRange.inRange(range)) {
18468 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18471 parent = parent.parentElement;
18476 // is ancestor a text element.
18477 var ac = range.commonAncestorContainer;
18478 if (ac.nodeType == 3) {
18479 ac = ac.parentNode;
18482 var ar = ac.childNodes;
18485 var other_nodes = [];
18486 var has_other_nodes = false;
18487 for (var i=0;i<ar.length;i++) {
18488 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18491 // fullly contained node.
18493 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18498 // probably selected..
18499 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18500 other_nodes.push(ar[i]);
18504 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18509 has_other_nodes = true;
18511 if (!nodes.length && other_nodes.length) {
18512 nodes= other_nodes;
18514 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18520 createRange: function(sel)
18522 // this has strange effects when using with
18523 // top toolbar - not sure if it's a great idea.
18524 //this.editor.contentWindow.focus();
18525 if (typeof sel != "undefined") {
18527 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18529 return this.doc.createRange();
18532 return this.doc.createRange();
18535 getParentElement: function()
18538 this.assignDocWin();
18539 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18541 var range = this.createRange(sel);
18544 var p = range.commonAncestorContainer;
18545 while (p.nodeType == 3) { // text node
18556 * Range intersection.. the hard stuff...
18560 * [ -- selected range --- ]
18564 * if end is before start or hits it. fail.
18565 * if start is after end or hits it fail.
18567 * if either hits (but other is outside. - then it's not
18573 // @see http://www.thismuchiknow.co.uk/?p=64.
18574 rangeIntersectsNode : function(range, node)
18576 var nodeRange = node.ownerDocument.createRange();
18578 nodeRange.selectNode(node);
18580 nodeRange.selectNodeContents(node);
18583 var rangeStartRange = range.cloneRange();
18584 rangeStartRange.collapse(true);
18586 var rangeEndRange = range.cloneRange();
18587 rangeEndRange.collapse(false);
18589 var nodeStartRange = nodeRange.cloneRange();
18590 nodeStartRange.collapse(true);
18592 var nodeEndRange = nodeRange.cloneRange();
18593 nodeEndRange.collapse(false);
18595 return rangeStartRange.compareBoundaryPoints(
18596 Range.START_TO_START, nodeEndRange) == -1 &&
18597 rangeEndRange.compareBoundaryPoints(
18598 Range.START_TO_START, nodeStartRange) == 1;
18602 rangeCompareNode : function(range, node)
18604 var nodeRange = node.ownerDocument.createRange();
18606 nodeRange.selectNode(node);
18608 nodeRange.selectNodeContents(node);
18612 range.collapse(true);
18614 nodeRange.collapse(true);
18616 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18617 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18619 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18621 var nodeIsBefore = ss == 1;
18622 var nodeIsAfter = ee == -1;
18624 if (nodeIsBefore && nodeIsAfter)
18626 if (!nodeIsBefore && nodeIsAfter)
18627 return 1; //right trailed.
18629 if (nodeIsBefore && !nodeIsAfter)
18630 return 2; // left trailed.
18635 // private? - in a new class?
18636 cleanUpPaste : function()
18638 // cleans up the whole document..
18639 Roo.log('cleanuppaste');
18641 this.cleanUpChildren(this.doc.body);
18642 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18643 if (clean != this.doc.body.innerHTML) {
18644 this.doc.body.innerHTML = clean;
18649 cleanWordChars : function(input) {// change the chars to hex code
18650 var he = Roo.HtmlEditorCore;
18652 var output = input;
18653 Roo.each(he.swapCodes, function(sw) {
18654 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18656 output = output.replace(swapper, sw[1]);
18663 cleanUpChildren : function (n)
18665 if (!n.childNodes.length) {
18668 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18669 this.cleanUpChild(n.childNodes[i]);
18676 cleanUpChild : function (node)
18679 //console.log(node);
18680 if (node.nodeName == "#text") {
18681 // clean up silly Windows -- stuff?
18684 if (node.nodeName == "#comment") {
18685 node.parentNode.removeChild(node);
18686 // clean up silly Windows -- stuff?
18689 var lcname = node.tagName.toLowerCase();
18690 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18691 // whitelist of tags..
18693 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18695 node.parentNode.removeChild(node);
18700 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18702 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18703 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18705 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18706 // remove_keep_children = true;
18709 if (remove_keep_children) {
18710 this.cleanUpChildren(node);
18711 // inserts everything just before this node...
18712 while (node.childNodes.length) {
18713 var cn = node.childNodes[0];
18714 node.removeChild(cn);
18715 node.parentNode.insertBefore(cn, node);
18717 node.parentNode.removeChild(node);
18721 if (!node.attributes || !node.attributes.length) {
18722 this.cleanUpChildren(node);
18726 function cleanAttr(n,v)
18729 if (v.match(/^\./) || v.match(/^\//)) {
18732 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18735 if (v.match(/^#/)) {
18738 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18739 node.removeAttribute(n);
18743 var cwhite = this.cwhite;
18744 var cblack = this.cblack;
18746 function cleanStyle(n,v)
18748 if (v.match(/expression/)) { //XSS?? should we even bother..
18749 node.removeAttribute(n);
18753 var parts = v.split(/;/);
18756 Roo.each(parts, function(p) {
18757 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18761 var l = p.split(':').shift().replace(/\s+/g,'');
18762 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18764 if ( cwhite.length && cblack.indexOf(l) > -1) {
18765 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18766 //node.removeAttribute(n);
18770 // only allow 'c whitelisted system attributes'
18771 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18772 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18773 //node.removeAttribute(n);
18783 if (clean.length) {
18784 node.setAttribute(n, clean.join(';'));
18786 node.removeAttribute(n);
18792 for (var i = node.attributes.length-1; i > -1 ; i--) {
18793 var a = node.attributes[i];
18796 if (a.name.toLowerCase().substr(0,2)=='on') {
18797 node.removeAttribute(a.name);
18800 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18801 node.removeAttribute(a.name);
18804 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18805 cleanAttr(a.name,a.value); // fixme..
18808 if (a.name == 'style') {
18809 cleanStyle(a.name,a.value);
18812 /// clean up MS crap..
18813 // tecnically this should be a list of valid class'es..
18816 if (a.name == 'class') {
18817 if (a.value.match(/^Mso/)) {
18818 node.className = '';
18821 if (a.value.match(/body/)) {
18822 node.className = '';
18833 this.cleanUpChildren(node);
18838 * Clean up MS wordisms...
18840 cleanWord : function(node)
18843 var cleanWordChildren = function()
18845 if (!node.childNodes.length) {
18848 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18849 _t.cleanWord(node.childNodes[i]);
18855 this.cleanWord(this.doc.body);
18858 if (node.nodeName == "#text") {
18859 // clean up silly Windows -- stuff?
18862 if (node.nodeName == "#comment") {
18863 node.parentNode.removeChild(node);
18864 // clean up silly Windows -- stuff?
18868 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18869 node.parentNode.removeChild(node);
18873 // remove - but keep children..
18874 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18875 while (node.childNodes.length) {
18876 var cn = node.childNodes[0];
18877 node.removeChild(cn);
18878 node.parentNode.insertBefore(cn, node);
18880 node.parentNode.removeChild(node);
18881 cleanWordChildren();
18885 if (node.className.length) {
18887 var cn = node.className.split(/\W+/);
18889 Roo.each(cn, function(cls) {
18890 if (cls.match(/Mso[a-zA-Z]+/)) {
18895 node.className = cna.length ? cna.join(' ') : '';
18897 node.removeAttribute("class");
18901 if (node.hasAttribute("lang")) {
18902 node.removeAttribute("lang");
18905 if (node.hasAttribute("style")) {
18907 var styles = node.getAttribute("style").split(";");
18909 Roo.each(styles, function(s) {
18910 if (!s.match(/:/)) {
18913 var kv = s.split(":");
18914 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18917 // what ever is left... we allow.
18920 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18921 if (!nstyle.length) {
18922 node.removeAttribute('style');
18926 cleanWordChildren();
18930 domToHTML : function(currentElement, depth, nopadtext) {
18932 depth = depth || 0;
18933 nopadtext = nopadtext || false;
18935 if (!currentElement) {
18936 return this.domToHTML(this.doc.body);
18939 //Roo.log(currentElement);
18941 var allText = false;
18942 var nodeName = currentElement.nodeName;
18943 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18945 if (nodeName == '#text') {
18947 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18952 if (nodeName != 'BODY') {
18955 // Prints the node tagName, such as <A>, <IMG>, etc
18958 for(i = 0; i < currentElement.attributes.length;i++) {
18960 var aname = currentElement.attributes.item(i).name;
18961 if (!currentElement.attributes.item(i).value.length) {
18964 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18967 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18976 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18979 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18984 // Traverse the tree
18986 var currentElementChild = currentElement.childNodes.item(i);
18987 var allText = true;
18988 var innerHTML = '';
18990 while (currentElementChild) {
18991 // Formatting code (indent the tree so it looks nice on the screen)
18992 var nopad = nopadtext;
18993 if (lastnode == 'SPAN') {
18997 if (currentElementChild.nodeName == '#text') {
18998 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18999 toadd = nopadtext ? toadd : toadd.trim();
19000 if (!nopad && toadd.length > 80) {
19001 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19003 innerHTML += toadd;
19006 currentElementChild = currentElement.childNodes.item(i);
19012 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19014 // Recursively traverse the tree structure of the child node
19015 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19016 lastnode = currentElementChild.nodeName;
19018 currentElementChild=currentElement.childNodes.item(i);
19024 // The remaining code is mostly for formatting the tree
19025 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19030 ret+= "</"+tagName+">";
19036 applyBlacklists : function()
19038 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19039 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19043 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19044 if (b.indexOf(tag) > -1) {
19047 this.white.push(tag);
19051 Roo.each(w, function(tag) {
19052 if (b.indexOf(tag) > -1) {
19055 if (this.white.indexOf(tag) > -1) {
19058 this.white.push(tag);
19063 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19064 if (w.indexOf(tag) > -1) {
19067 this.black.push(tag);
19071 Roo.each(b, function(tag) {
19072 if (w.indexOf(tag) > -1) {
19075 if (this.black.indexOf(tag) > -1) {
19078 this.black.push(tag);
19083 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19084 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19088 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19089 if (b.indexOf(tag) > -1) {
19092 this.cwhite.push(tag);
19096 Roo.each(w, function(tag) {
19097 if (b.indexOf(tag) > -1) {
19100 if (this.cwhite.indexOf(tag) > -1) {
19103 this.cwhite.push(tag);
19108 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19109 if (w.indexOf(tag) > -1) {
19112 this.cblack.push(tag);
19116 Roo.each(b, function(tag) {
19117 if (w.indexOf(tag) > -1) {
19120 if (this.cblack.indexOf(tag) > -1) {
19123 this.cblack.push(tag);
19128 setStylesheets : function(stylesheets)
19130 if(typeof(stylesheets) == 'string'){
19131 Roo.get(this.iframe.contentDocument.head).createChild({
19133 rel : 'stylesheet',
19142 Roo.each(stylesheets, function(s) {
19147 Roo.get(_this.iframe.contentDocument.head).createChild({
19149 rel : 'stylesheet',
19158 removeStylesheets : function()
19162 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19167 // hide stuff that is not compatible
19181 * @event specialkey
19185 * @cfg {String} fieldClass @hide
19188 * @cfg {String} focusClass @hide
19191 * @cfg {String} autoCreate @hide
19194 * @cfg {String} inputType @hide
19197 * @cfg {String} invalidClass @hide
19200 * @cfg {String} invalidText @hide
19203 * @cfg {String} msgFx @hide
19206 * @cfg {String} validateOnBlur @hide
19210 Roo.HtmlEditorCore.white = [
19211 'area', 'br', 'img', 'input', 'hr', 'wbr',
19213 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19214 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19215 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19216 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19217 'table', 'ul', 'xmp',
19219 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19222 'dir', 'menu', 'ol', 'ul', 'dl',
19228 Roo.HtmlEditorCore.black = [
19229 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19231 'base', 'basefont', 'bgsound', 'blink', 'body',
19232 'frame', 'frameset', 'head', 'html', 'ilayer',
19233 'iframe', 'layer', 'link', 'meta', 'object',
19234 'script', 'style' ,'title', 'xml' // clean later..
19236 Roo.HtmlEditorCore.clean = [
19237 'script', 'style', 'title', 'xml'
19239 Roo.HtmlEditorCore.remove = [
19244 Roo.HtmlEditorCore.ablack = [
19248 Roo.HtmlEditorCore.aclean = [
19249 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19253 Roo.HtmlEditorCore.pwhite= [
19254 'http', 'https', 'mailto'
19257 // white listed style attributes.
19258 Roo.HtmlEditorCore.cwhite= [
19259 // 'text-align', /// default is to allow most things..
19265 // black listed style attributes.
19266 Roo.HtmlEditorCore.cblack= [
19267 // 'font-size' -- this can be set by the project
19271 Roo.HtmlEditorCore.swapCodes =[
19290 * @class Roo.bootstrap.HtmlEditor
19291 * @extends Roo.bootstrap.TextArea
19292 * Bootstrap HtmlEditor class
19295 * Create a new HtmlEditor
19296 * @param {Object} config The config object
19299 Roo.bootstrap.HtmlEditor = function(config){
19300 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19301 if (!this.toolbars) {
19302 this.toolbars = [];
19304 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19307 * @event initialize
19308 * Fires when the editor is fully initialized (including the iframe)
19309 * @param {HtmlEditor} this
19314 * Fires when the editor is first receives the focus. Any insertion must wait
19315 * until after this event.
19316 * @param {HtmlEditor} this
19320 * @event beforesync
19321 * Fires before the textarea is updated with content from the editor iframe. Return false
19322 * to cancel the sync.
19323 * @param {HtmlEditor} this
19324 * @param {String} html
19328 * @event beforepush
19329 * Fires before the iframe editor is updated with content from the textarea. Return false
19330 * to cancel the push.
19331 * @param {HtmlEditor} this
19332 * @param {String} html
19337 * Fires when the textarea is updated with content from the editor iframe.
19338 * @param {HtmlEditor} this
19339 * @param {String} html
19344 * Fires when the iframe editor is updated with content from the textarea.
19345 * @param {HtmlEditor} this
19346 * @param {String} html
19350 * @event editmodechange
19351 * Fires when the editor switches edit modes
19352 * @param {HtmlEditor} this
19353 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19355 editmodechange: true,
19357 * @event editorevent
19358 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19359 * @param {HtmlEditor} this
19363 * @event firstfocus
19364 * Fires when on first focus - needed by toolbars..
19365 * @param {HtmlEditor} this
19370 * Auto save the htmlEditor value as a file into Events
19371 * @param {HtmlEditor} this
19375 * @event savedpreview
19376 * preview the saved version of htmlEditor
19377 * @param {HtmlEditor} this
19384 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19388 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19393 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19398 * @cfg {Number} height (in pixels)
19402 * @cfg {Number} width (in pixels)
19407 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19410 stylesheets: false,
19415 // private properties
19416 validationEvent : false,
19418 initialized : false,
19421 onFocus : Roo.emptyFn,
19423 hideMode:'offsets',
19426 tbContainer : false,
19428 toolbarContainer :function() {
19429 return this.wrap.select('.x-html-editor-tb',true).first();
19433 * Protected method that will not generally be called directly. It
19434 * is called when the editor creates its toolbar. Override this method if you need to
19435 * add custom toolbar buttons.
19436 * @param {HtmlEditor} editor
19438 createToolbar : function(){
19440 Roo.log("create toolbars");
19442 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19443 this.toolbars[0].render(this.toolbarContainer());
19447 // if (!editor.toolbars || !editor.toolbars.length) {
19448 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19451 // for (var i =0 ; i < editor.toolbars.length;i++) {
19452 // editor.toolbars[i] = Roo.factory(
19453 // typeof(editor.toolbars[i]) == 'string' ?
19454 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19455 // Roo.bootstrap.HtmlEditor);
19456 // editor.toolbars[i].init(editor);
19462 onRender : function(ct, position)
19464 // Roo.log("Call onRender: " + this.xtype);
19466 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19468 this.wrap = this.inputEl().wrap({
19469 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19472 this.editorcore.onRender(ct, position);
19474 if (this.resizable) {
19475 this.resizeEl = new Roo.Resizable(this.wrap, {
19479 minHeight : this.height,
19480 height: this.height,
19481 handles : this.resizable,
19484 resize : function(r, w, h) {
19485 _t.onResize(w,h); // -something
19491 this.createToolbar(this);
19494 if(!this.width && this.resizable){
19495 this.setSize(this.wrap.getSize());
19497 if (this.resizeEl) {
19498 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19499 // should trigger onReize..
19505 onResize : function(w, h)
19507 Roo.log('resize: ' +w + ',' + h );
19508 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19512 if(this.inputEl() ){
19513 if(typeof w == 'number'){
19514 var aw = w - this.wrap.getFrameWidth('lr');
19515 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19518 if(typeof h == 'number'){
19519 var tbh = -11; // fixme it needs to tool bar size!
19520 for (var i =0; i < this.toolbars.length;i++) {
19521 // fixme - ask toolbars for heights?
19522 tbh += this.toolbars[i].el.getHeight();
19523 //if (this.toolbars[i].footer) {
19524 // tbh += this.toolbars[i].footer.el.getHeight();
19532 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19533 ah -= 5; // knock a few pixes off for look..
19534 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19538 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19539 this.editorcore.onResize(ew,eh);
19544 * Toggles the editor between standard and source edit mode.
19545 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19547 toggleSourceEdit : function(sourceEditMode)
19549 this.editorcore.toggleSourceEdit(sourceEditMode);
19551 if(this.editorcore.sourceEditMode){
19552 Roo.log('editor - showing textarea');
19555 // Roo.log(this.syncValue());
19557 this.inputEl().removeClass(['hide', 'x-hidden']);
19558 this.inputEl().dom.removeAttribute('tabIndex');
19559 this.inputEl().focus();
19561 Roo.log('editor - hiding textarea');
19563 // Roo.log(this.pushValue());
19566 this.inputEl().addClass(['hide', 'x-hidden']);
19567 this.inputEl().dom.setAttribute('tabIndex', -1);
19568 //this.deferFocus();
19571 if(this.resizable){
19572 this.setSize(this.wrap.getSize());
19575 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19578 // private (for BoxComponent)
19579 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19581 // private (for BoxComponent)
19582 getResizeEl : function(){
19586 // private (for BoxComponent)
19587 getPositionEl : function(){
19592 initEvents : function(){
19593 this.originalValue = this.getValue();
19597 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19600 // markInvalid : Roo.emptyFn,
19602 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19605 // clearInvalid : Roo.emptyFn,
19607 setValue : function(v){
19608 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19609 this.editorcore.pushValue();
19614 deferFocus : function(){
19615 this.focus.defer(10, this);
19619 focus : function(){
19620 this.editorcore.focus();
19626 onDestroy : function(){
19632 for (var i =0; i < this.toolbars.length;i++) {
19633 // fixme - ask toolbars for heights?
19634 this.toolbars[i].onDestroy();
19637 this.wrap.dom.innerHTML = '';
19638 this.wrap.remove();
19643 onFirstFocus : function(){
19644 //Roo.log("onFirstFocus");
19645 this.editorcore.onFirstFocus();
19646 for (var i =0; i < this.toolbars.length;i++) {
19647 this.toolbars[i].onFirstFocus();
19653 syncValue : function()
19655 this.editorcore.syncValue();
19658 pushValue : function()
19660 this.editorcore.pushValue();
19664 // hide stuff that is not compatible
19678 * @event specialkey
19682 * @cfg {String} fieldClass @hide
19685 * @cfg {String} focusClass @hide
19688 * @cfg {String} autoCreate @hide
19691 * @cfg {String} inputType @hide
19694 * @cfg {String} invalidClass @hide
19697 * @cfg {String} invalidText @hide
19700 * @cfg {String} msgFx @hide
19703 * @cfg {String} validateOnBlur @hide
19712 Roo.namespace('Roo.bootstrap.htmleditor');
19714 * @class Roo.bootstrap.HtmlEditorToolbar1
19719 new Roo.bootstrap.HtmlEditor({
19722 new Roo.bootstrap.HtmlEditorToolbar1({
19723 disable : { fonts: 1 , format: 1, ..., ... , ...],
19729 * @cfg {Object} disable List of elements to disable..
19730 * @cfg {Array} btns List of additional buttons.
19734 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19737 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19740 Roo.apply(this, config);
19742 // default disabled, based on 'good practice'..
19743 this.disable = this.disable || {};
19744 Roo.applyIf(this.disable, {
19747 specialElements : true
19749 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19751 this.editor = config.editor;
19752 this.editorcore = config.editor.editorcore;
19754 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19756 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19757 // dont call parent... till later.
19759 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19764 editorcore : false,
19769 "h1","h2","h3","h4","h5","h6",
19771 "abbr", "acronym", "address", "cite", "samp", "var",
19775 onRender : function(ct, position)
19777 // Roo.log("Call onRender: " + this.xtype);
19779 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19781 this.el.dom.style.marginBottom = '0';
19783 var editorcore = this.editorcore;
19784 var editor= this.editor;
19787 var btn = function(id,cmd , toggle, handler){
19789 var event = toggle ? 'toggle' : 'click';
19794 xns: Roo.bootstrap,
19797 enableToggle:toggle !== false,
19799 pressed : toggle ? false : null,
19802 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19803 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19812 xns: Roo.bootstrap,
19813 glyphicon : 'font',
19817 xns: Roo.bootstrap,
19821 Roo.each(this.formats, function(f) {
19822 style.menu.items.push({
19824 xns: Roo.bootstrap,
19825 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19830 editorcore.insertTag(this.tagname);
19837 children.push(style);
19840 btn('bold',false,true);
19841 btn('italic',false,true);
19842 btn('align-left', 'justifyleft',true);
19843 btn('align-center', 'justifycenter',true);
19844 btn('align-right' , 'justifyright',true);
19845 btn('link', false, false, function(btn) {
19846 //Roo.log("create link?");
19847 var url = prompt(this.createLinkText, this.defaultLinkValue);
19848 if(url && url != 'http:/'+'/'){
19849 this.editorcore.relayCmd('createlink', url);
19852 btn('list','insertunorderedlist',true);
19853 btn('pencil', false,true, function(btn){
19856 this.toggleSourceEdit(btn.pressed);
19862 xns: Roo.bootstrap,
19867 xns: Roo.bootstrap,
19872 cog.menu.items.push({
19874 xns: Roo.bootstrap,
19875 html : Clean styles,
19880 editorcore.insertTag(this.tagname);
19889 this.xtype = 'NavSimplebar';
19891 for(var i=0;i< children.length;i++) {
19893 this.buttons.add(this.addxtypeChild(children[i]));
19897 editor.on('editorevent', this.updateToolbar, this);
19899 onBtnClick : function(id)
19901 this.editorcore.relayCmd(id);
19902 this.editorcore.focus();
19906 * Protected method that will not generally be called directly. It triggers
19907 * a toolbar update by reading the markup state of the current selection in the editor.
19909 updateToolbar: function(){
19911 if(!this.editorcore.activated){
19912 this.editor.onFirstFocus(); // is this neeed?
19916 var btns = this.buttons;
19917 var doc = this.editorcore.doc;
19918 btns.get('bold').setActive(doc.queryCommandState('bold'));
19919 btns.get('italic').setActive(doc.queryCommandState('italic'));
19920 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19922 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19923 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19924 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19926 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19927 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19930 var ans = this.editorcore.getAllAncestors();
19931 if (this.formatCombo) {
19934 var store = this.formatCombo.store;
19935 this.formatCombo.setValue("");
19936 for (var i =0; i < ans.length;i++) {
19937 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19939 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19947 // hides menus... - so this cant be on a menu...
19948 Roo.bootstrap.MenuMgr.hideAll();
19950 Roo.bootstrap.MenuMgr.hideAll();
19951 //this.editorsyncValue();
19953 onFirstFocus: function() {
19954 this.buttons.each(function(item){
19958 toggleSourceEdit : function(sourceEditMode){
19961 if(sourceEditMode){
19962 Roo.log("disabling buttons");
19963 this.buttons.each( function(item){
19964 if(item.cmd != 'pencil'){
19970 Roo.log("enabling buttons");
19971 if(this.editorcore.initialized){
19972 this.buttons.each( function(item){
19978 Roo.log("calling toggole on editor");
19979 // tell the editor that it's been pressed..
19980 this.editor.toggleSourceEdit(sourceEditMode);
19990 * @class Roo.bootstrap.Table.AbstractSelectionModel
19991 * @extends Roo.util.Observable
19992 * Abstract base class for grid SelectionModels. It provides the interface that should be
19993 * implemented by descendant classes. This class should not be directly instantiated.
19996 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19997 this.locked = false;
19998 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20002 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20003 /** @ignore Called by the grid automatically. Do not call directly. */
20004 init : function(grid){
20010 * Locks the selections.
20013 this.locked = true;
20017 * Unlocks the selections.
20019 unlock : function(){
20020 this.locked = false;
20024 * Returns true if the selections are locked.
20025 * @return {Boolean}
20027 isLocked : function(){
20028 return this.locked;
20032 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20033 * @class Roo.bootstrap.Table.RowSelectionModel
20034 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20035 * It supports multiple selections and keyboard selection/navigation.
20037 * @param {Object} config
20040 Roo.bootstrap.Table.RowSelectionModel = function(config){
20041 Roo.apply(this, config);
20042 this.selections = new Roo.util.MixedCollection(false, function(o){
20047 this.lastActive = false;
20051 * @event selectionchange
20052 * Fires when the selection changes
20053 * @param {SelectionModel} this
20055 "selectionchange" : true,
20057 * @event afterselectionchange
20058 * Fires after the selection changes (eg. by key press or clicking)
20059 * @param {SelectionModel} this
20061 "afterselectionchange" : true,
20063 * @event beforerowselect
20064 * Fires when a row is selected being selected, return false to cancel.
20065 * @param {SelectionModel} this
20066 * @param {Number} rowIndex The selected index
20067 * @param {Boolean} keepExisting False if other selections will be cleared
20069 "beforerowselect" : true,
20072 * Fires when a row is selected.
20073 * @param {SelectionModel} this
20074 * @param {Number} rowIndex The selected index
20075 * @param {Roo.data.Record} r The record
20077 "rowselect" : true,
20079 * @event rowdeselect
20080 * Fires when a row is deselected.
20081 * @param {SelectionModel} this
20082 * @param {Number} rowIndex The selected index
20084 "rowdeselect" : true
20086 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20087 this.locked = false;
20090 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20092 * @cfg {Boolean} singleSelect
20093 * True to allow selection of only one row at a time (defaults to false)
20095 singleSelect : false,
20098 initEvents : function(){
20100 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20101 this.grid.on("mousedown", this.handleMouseDown, this);
20102 }else{ // allow click to work like normal
20103 this.grid.on("rowclick", this.handleDragableRowClick, this);
20106 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20107 "up" : function(e){
20109 this.selectPrevious(e.shiftKey);
20110 }else if(this.last !== false && this.lastActive !== false){
20111 var last = this.last;
20112 this.selectRange(this.last, this.lastActive-1);
20113 this.grid.getView().focusRow(this.lastActive);
20114 if(last !== false){
20118 this.selectFirstRow();
20120 this.fireEvent("afterselectionchange", this);
20122 "down" : function(e){
20124 this.selectNext(e.shiftKey);
20125 }else if(this.last !== false && this.lastActive !== false){
20126 var last = this.last;
20127 this.selectRange(this.last, this.lastActive+1);
20128 this.grid.getView().focusRow(this.lastActive);
20129 if(last !== false){
20133 this.selectFirstRow();
20135 this.fireEvent("afterselectionchange", this);
20140 var view = this.grid.view;
20141 view.on("refresh", this.onRefresh, this);
20142 view.on("rowupdated", this.onRowUpdated, this);
20143 view.on("rowremoved", this.onRemove, this);
20147 onRefresh : function(){
20148 var ds = this.grid.dataSource, i, v = this.grid.view;
20149 var s = this.selections;
20150 s.each(function(r){
20151 if((i = ds.indexOfId(r.id)) != -1){
20160 onRemove : function(v, index, r){
20161 this.selections.remove(r);
20165 onRowUpdated : function(v, index, r){
20166 if(this.isSelected(r)){
20167 v.onRowSelect(index);
20173 * @param {Array} records The records to select
20174 * @param {Boolean} keepExisting (optional) True to keep existing selections
20176 selectRecords : function(records, keepExisting){
20178 this.clearSelections();
20180 var ds = this.grid.dataSource;
20181 for(var i = 0, len = records.length; i < len; i++){
20182 this.selectRow(ds.indexOf(records[i]), true);
20187 * Gets the number of selected rows.
20190 getCount : function(){
20191 return this.selections.length;
20195 * Selects the first row in the grid.
20197 selectFirstRow : function(){
20202 * Select the last row.
20203 * @param {Boolean} keepExisting (optional) True to keep existing selections
20205 selectLastRow : function(keepExisting){
20206 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20210 * Selects the row immediately following the last selected row.
20211 * @param {Boolean} keepExisting (optional) True to keep existing selections
20213 selectNext : function(keepExisting){
20214 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20215 this.selectRow(this.last+1, keepExisting);
20216 this.grid.getView().focusRow(this.last);
20221 * Selects the row that precedes the last selected row.
20222 * @param {Boolean} keepExisting (optional) True to keep existing selections
20224 selectPrevious : function(keepExisting){
20226 this.selectRow(this.last-1, keepExisting);
20227 this.grid.getView().focusRow(this.last);
20232 * Returns the selected records
20233 * @return {Array} Array of selected records
20235 getSelections : function(){
20236 return [].concat(this.selections.items);
20240 * Returns the first selected record.
20243 getSelected : function(){
20244 return this.selections.itemAt(0);
20249 * Clears all selections.
20251 clearSelections : function(fast){
20252 if(this.locked) return;
20254 var ds = this.grid.dataSource;
20255 var s = this.selections;
20256 s.each(function(r){
20257 this.deselectRow(ds.indexOfId(r.id));
20261 this.selections.clear();
20268 * Selects all rows.
20270 selectAll : function(){
20271 if(this.locked) return;
20272 this.selections.clear();
20273 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20274 this.selectRow(i, true);
20279 * Returns True if there is a selection.
20280 * @return {Boolean}
20282 hasSelection : function(){
20283 return this.selections.length > 0;
20287 * Returns True if the specified row is selected.
20288 * @param {Number/Record} record The record or index of the record to check
20289 * @return {Boolean}
20291 isSelected : function(index){
20292 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20293 return (r && this.selections.key(r.id) ? true : false);
20297 * Returns True if the specified record id is selected.
20298 * @param {String} id The id of record to check
20299 * @return {Boolean}
20301 isIdSelected : function(id){
20302 return (this.selections.key(id) ? true : false);
20306 handleMouseDown : function(e, t){
20307 var view = this.grid.getView(), rowIndex;
20308 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20311 if(e.shiftKey && this.last !== false){
20312 var last = this.last;
20313 this.selectRange(last, rowIndex, e.ctrlKey);
20314 this.last = last; // reset the last
20315 view.focusRow(rowIndex);
20317 var isSelected = this.isSelected(rowIndex);
20318 if(e.button !== 0 && isSelected){
20319 view.focusRow(rowIndex);
20320 }else if(e.ctrlKey && isSelected){
20321 this.deselectRow(rowIndex);
20322 }else if(!isSelected){
20323 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20324 view.focusRow(rowIndex);
20327 this.fireEvent("afterselectionchange", this);
20330 handleDragableRowClick : function(grid, rowIndex, e)
20332 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20333 this.selectRow(rowIndex, false);
20334 grid.view.focusRow(rowIndex);
20335 this.fireEvent("afterselectionchange", this);
20340 * Selects multiple rows.
20341 * @param {Array} rows Array of the indexes of the row to select
20342 * @param {Boolean} keepExisting (optional) True to keep existing selections
20344 selectRows : function(rows, keepExisting){
20346 this.clearSelections();
20348 for(var i = 0, len = rows.length; i < len; i++){
20349 this.selectRow(rows[i], true);
20354 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20355 * @param {Number} startRow The index of the first row in the range
20356 * @param {Number} endRow The index of the last row in the range
20357 * @param {Boolean} keepExisting (optional) True to retain existing selections
20359 selectRange : function(startRow, endRow, keepExisting){
20360 if(this.locked) return;
20362 this.clearSelections();
20364 if(startRow <= endRow){
20365 for(var i = startRow; i <= endRow; i++){
20366 this.selectRow(i, true);
20369 for(var i = startRow; i >= endRow; i--){
20370 this.selectRow(i, true);
20376 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20377 * @param {Number} startRow The index of the first row in the range
20378 * @param {Number} endRow The index of the last row in the range
20380 deselectRange : function(startRow, endRow, preventViewNotify){
20381 if(this.locked) return;
20382 for(var i = startRow; i <= endRow; i++){
20383 this.deselectRow(i, preventViewNotify);
20389 * @param {Number} row The index of the row to select
20390 * @param {Boolean} keepExisting (optional) True to keep existing selections
20392 selectRow : function(index, keepExisting, preventViewNotify){
20393 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20394 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20395 if(!keepExisting || this.singleSelect){
20396 this.clearSelections();
20398 var r = this.grid.dataSource.getAt(index);
20399 this.selections.add(r);
20400 this.last = this.lastActive = index;
20401 if(!preventViewNotify){
20402 this.grid.getView().onRowSelect(index);
20404 this.fireEvent("rowselect", this, index, r);
20405 this.fireEvent("selectionchange", this);
20411 * @param {Number} row The index of the row to deselect
20413 deselectRow : function(index, preventViewNotify){
20414 if(this.locked) return;
20415 if(this.last == index){
20418 if(this.lastActive == index){
20419 this.lastActive = false;
20421 var r = this.grid.dataSource.getAt(index);
20422 this.selections.remove(r);
20423 if(!preventViewNotify){
20424 this.grid.getView().onRowDeselect(index);
20426 this.fireEvent("rowdeselect", this, index);
20427 this.fireEvent("selectionchange", this);
20431 restoreLast : function(){
20433 this.last = this._last;
20438 acceptsNav : function(row, col, cm){
20439 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20443 onEditorKey : function(field, e){
20444 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20449 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20451 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20453 }else if(k == e.ENTER && !e.ctrlKey){
20457 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20459 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20461 }else if(k == e.ESC){
20465 g.startEditing(newCell[0], newCell[1]);
20470 * Ext JS Library 1.1.1
20471 * Copyright(c) 2006-2007, Ext JS, LLC.
20473 * Originally Released Under LGPL - original licence link has changed is not relivant.
20476 * <script type="text/javascript">
20480 * @class Roo.bootstrap.PagingToolbar
20482 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20484 * Create a new PagingToolbar
20485 * @param {Object} config The config object
20487 Roo.bootstrap.PagingToolbar = function(config)
20489 // old args format still supported... - xtype is prefered..
20490 // created from xtype...
20491 var ds = config.dataSource;
20492 this.toolbarItems = [];
20493 if (config.items) {
20494 this.toolbarItems = config.items;
20495 // config.items = [];
20498 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20505 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20509 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20511 * @cfg {Roo.data.Store} dataSource
20512 * The underlying data store providing the paged data
20515 * @cfg {String/HTMLElement/Element} container
20516 * container The id or element that will contain the toolbar
20519 * @cfg {Boolean} displayInfo
20520 * True to display the displayMsg (defaults to false)
20523 * @cfg {Number} pageSize
20524 * The number of records to display per page (defaults to 20)
20528 * @cfg {String} displayMsg
20529 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20531 displayMsg : 'Displaying {0} - {1} of {2}',
20533 * @cfg {String} emptyMsg
20534 * The message to display when no records are found (defaults to "No data to display")
20536 emptyMsg : 'No data to display',
20538 * Customizable piece of the default paging text (defaults to "Page")
20541 beforePageText : "Page",
20543 * Customizable piece of the default paging text (defaults to "of %0")
20546 afterPageText : "of {0}",
20548 * Customizable piece of the default paging text (defaults to "First Page")
20551 firstText : "First Page",
20553 * Customizable piece of the default paging text (defaults to "Previous Page")
20556 prevText : "Previous Page",
20558 * Customizable piece of the default paging text (defaults to "Next Page")
20561 nextText : "Next Page",
20563 * Customizable piece of the default paging text (defaults to "Last Page")
20566 lastText : "Last Page",
20568 * Customizable piece of the default paging text (defaults to "Refresh")
20571 refreshText : "Refresh",
20575 onRender : function(ct, position)
20577 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20578 this.navgroup.parentId = this.id;
20579 this.navgroup.onRender(this.el, null);
20580 // add the buttons to the navgroup
20582 if(this.displayInfo){
20583 Roo.log(this.el.select('ul.navbar-nav',true).first());
20584 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20585 this.displayEl = this.el.select('.x-paging-info', true).first();
20586 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20587 // this.displayEl = navel.el.select('span',true).first();
20593 Roo.each(_this.buttons, function(e){
20594 Roo.factory(e).onRender(_this.el, null);
20598 Roo.each(_this.toolbarItems, function(e) {
20599 _this.navgroup.addItem(e);
20603 this.first = this.navgroup.addItem({
20604 tooltip: this.firstText,
20606 icon : 'fa fa-backward',
20608 preventDefault: true,
20609 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20612 this.prev = this.navgroup.addItem({
20613 tooltip: this.prevText,
20615 icon : 'fa fa-step-backward',
20617 preventDefault: true,
20618 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20620 //this.addSeparator();
20623 var field = this.navgroup.addItem( {
20625 cls : 'x-paging-position',
20627 html : this.beforePageText +
20628 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20629 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20632 this.field = field.el.select('input', true).first();
20633 this.field.on("keydown", this.onPagingKeydown, this);
20634 this.field.on("focus", function(){this.dom.select();});
20637 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20638 //this.field.setHeight(18);
20639 //this.addSeparator();
20640 this.next = this.navgroup.addItem({
20641 tooltip: this.nextText,
20643 html : ' <i class="fa fa-step-forward">',
20645 preventDefault: true,
20646 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20648 this.last = this.navgroup.addItem({
20649 tooltip: this.lastText,
20650 icon : 'fa fa-forward',
20653 preventDefault: true,
20654 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20656 //this.addSeparator();
20657 this.loading = this.navgroup.addItem({
20658 tooltip: this.refreshText,
20659 icon: 'fa fa-refresh',
20660 preventDefault: true,
20661 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20667 updateInfo : function(){
20668 if(this.displayEl){
20669 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20670 var msg = count == 0 ?
20674 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20676 this.displayEl.update(msg);
20681 onLoad : function(ds, r, o){
20682 this.cursor = o.params ? o.params.start : 0;
20683 var d = this.getPageData(),
20687 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20688 this.field.dom.value = ap;
20689 this.first.setDisabled(ap == 1);
20690 this.prev.setDisabled(ap == 1);
20691 this.next.setDisabled(ap == ps);
20692 this.last.setDisabled(ap == ps);
20693 this.loading.enable();
20698 getPageData : function(){
20699 var total = this.ds.getTotalCount();
20702 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20703 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20708 onLoadError : function(){
20709 this.loading.enable();
20713 onPagingKeydown : function(e){
20714 var k = e.getKey();
20715 var d = this.getPageData();
20717 var v = this.field.dom.value, pageNum;
20718 if(!v || isNaN(pageNum = parseInt(v, 10))){
20719 this.field.dom.value = d.activePage;
20722 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20723 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20726 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))
20728 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20729 this.field.dom.value = pageNum;
20730 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20733 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20735 var v = this.field.dom.value, pageNum;
20736 var increment = (e.shiftKey) ? 10 : 1;
20737 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20739 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20740 this.field.dom.value = d.activePage;
20743 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20745 this.field.dom.value = parseInt(v, 10) + increment;
20746 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20747 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20754 beforeLoad : function(){
20756 this.loading.disable();
20761 onClick : function(which){
20770 ds.load({params:{start: 0, limit: this.pageSize}});
20773 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20776 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20779 var total = ds.getTotalCount();
20780 var extra = total % this.pageSize;
20781 var lastStart = extra ? (total - extra) : total-this.pageSize;
20782 ds.load({params:{start: lastStart, limit: this.pageSize}});
20785 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20791 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20792 * @param {Roo.data.Store} store The data store to unbind
20794 unbind : function(ds){
20795 ds.un("beforeload", this.beforeLoad, this);
20796 ds.un("load", this.onLoad, this);
20797 ds.un("loadexception", this.onLoadError, this);
20798 ds.un("remove", this.updateInfo, this);
20799 ds.un("add", this.updateInfo, this);
20800 this.ds = undefined;
20804 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20805 * @param {Roo.data.Store} store The data store to bind
20807 bind : function(ds){
20808 ds.on("beforeload", this.beforeLoad, this);
20809 ds.on("load", this.onLoad, this);
20810 ds.on("loadexception", this.onLoadError, this);
20811 ds.on("remove", this.updateInfo, this);
20812 ds.on("add", this.updateInfo, this);
20823 * @class Roo.bootstrap.MessageBar
20824 * @extends Roo.bootstrap.Component
20825 * Bootstrap MessageBar class
20826 * @cfg {String} html contents of the MessageBar
20827 * @cfg {String} weight (info | success | warning | danger) default info
20828 * @cfg {String} beforeClass insert the bar before the given class
20829 * @cfg {Boolean} closable (true | false) default false
20830 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20833 * Create a new Element
20834 * @param {Object} config The config object
20837 Roo.bootstrap.MessageBar = function(config){
20838 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20841 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20847 beforeClass: 'bootstrap-sticky-wrap',
20849 getAutoCreate : function(){
20853 cls: 'alert alert-dismissable alert-' + this.weight,
20858 html: this.html || ''
20864 cfg.cls += ' alert-messages-fixed';
20878 onRender : function(ct, position)
20880 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20883 var cfg = Roo.apply({}, this.getAutoCreate());
20887 cfg.cls += ' ' + this.cls;
20890 cfg.style = this.style;
20892 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20894 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20897 this.el.select('>button.close').on('click', this.hide, this);
20903 if (!this.rendered) {
20909 this.fireEvent('show', this);
20915 if (!this.rendered) {
20921 this.fireEvent('hide', this);
20924 update : function()
20926 // var e = this.el.dom.firstChild;
20928 // if(this.closable){
20929 // e = e.nextSibling;
20932 // e.data = this.html || '';
20934 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20950 * @class Roo.bootstrap.Graph
20951 * @extends Roo.bootstrap.Component
20952 * Bootstrap Graph class
20956 @cfg {String} graphtype bar | vbar | pie
20957 @cfg {number} g_x coodinator | centre x (pie)
20958 @cfg {number} g_y coodinator | centre y (pie)
20959 @cfg {number} g_r radius (pie)
20960 @cfg {number} g_height height of the chart (respected by all elements in the set)
20961 @cfg {number} g_width width of the chart (respected by all elements in the set)
20962 @cfg {Object} title The title of the chart
20965 -opts (object) options for the chart
20967 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20968 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20970 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.
20971 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20973 o stretch (boolean)
20975 -opts (object) options for the pie
20978 o startAngle (number)
20979 o endAngle (number)
20983 * Create a new Input
20984 * @param {Object} config The config object
20987 Roo.bootstrap.Graph = function(config){
20988 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20994 * The img click event for the img.
20995 * @param {Roo.EventObject} e
21001 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21012 //g_colors: this.colors,
21019 getAutoCreate : function(){
21030 onRender : function(ct,position){
21031 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21032 this.raphael = Raphael(this.el.dom);
21034 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21035 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21036 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21037 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21039 r.text(160, 10, "Single Series Chart").attr(txtattr);
21040 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21041 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21042 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21044 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21045 r.barchart(330, 10, 300, 220, data1);
21046 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21047 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21050 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21051 // r.barchart(30, 30, 560, 250, xdata, {
21052 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21053 // axis : "0 0 1 1",
21054 // axisxlabels : xdata
21055 // //yvalues : cols,
21058 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21060 // this.load(null,xdata,{
21061 // axis : "0 0 1 1",
21062 // axisxlabels : xdata
21067 load : function(graphtype,xdata,opts){
21068 this.raphael.clear();
21070 graphtype = this.graphtype;
21075 var r = this.raphael,
21076 fin = function () {
21077 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21079 fout = function () {
21080 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21082 pfin = function() {
21083 this.sector.stop();
21084 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21087 this.label[0].stop();
21088 this.label[0].attr({ r: 7.5 });
21089 this.label[1].attr({ "font-weight": 800 });
21092 pfout = function() {
21093 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21096 this.label[0].animate({ r: 5 }, 500, "bounce");
21097 this.label[1].attr({ "font-weight": 400 });
21103 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21106 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21109 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21110 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21112 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21119 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21124 setTitle: function(o)
21129 initEvents: function() {
21132 this.el.on('click', this.onClick, this);
21136 onClick : function(e)
21138 Roo.log('img onclick');
21139 this.fireEvent('click', this, e);
21151 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21154 * @class Roo.bootstrap.dash.NumberBox
21155 * @extends Roo.bootstrap.Component
21156 * Bootstrap NumberBox class
21157 * @cfg {String} headline Box headline
21158 * @cfg {String} content Box content
21159 * @cfg {String} icon Box icon
21160 * @cfg {String} footer Footer text
21161 * @cfg {String} fhref Footer href
21164 * Create a new NumberBox
21165 * @param {Object} config The config object
21169 Roo.bootstrap.dash.NumberBox = function(config){
21170 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21174 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21183 getAutoCreate : function(){
21187 cls : 'small-box ',
21195 cls : 'roo-headline',
21196 html : this.headline
21200 cls : 'roo-content',
21201 html : this.content
21215 cls : 'ion ' + this.icon
21224 cls : 'small-box-footer',
21225 href : this.fhref || '#',
21229 cfg.cn.push(footer);
21236 onRender : function(ct,position){
21237 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21244 setHeadline: function (value)
21246 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21249 setFooter: function (value, href)
21251 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21254 this.el.select('a.small-box-footer',true).first().attr('href', href);
21259 setContent: function (value)
21261 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21264 initEvents: function()
21278 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21281 * @class Roo.bootstrap.dash.TabBox
21282 * @extends Roo.bootstrap.Component
21283 * Bootstrap TabBox class
21284 * @cfg {String} title Title of the TabBox
21285 * @cfg {String} icon Icon of the TabBox
21286 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21287 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21290 * Create a new TabBox
21291 * @param {Object} config The config object
21295 Roo.bootstrap.dash.TabBox = function(config){
21296 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21301 * When a pane is added
21302 * @param {Roo.bootstrap.dash.TabPane} pane
21306 * @event activatepane
21307 * When a pane is activated
21308 * @param {Roo.bootstrap.dash.TabPane} pane
21310 "activatepane" : true
21318 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21323 tabScrollable : false,
21325 getChildContainer : function()
21327 return this.el.select('.tab-content', true).first();
21330 getAutoCreate : function(){
21334 cls: 'pull-left header',
21342 cls: 'fa ' + this.icon
21348 cls: 'nav nav-tabs pull-right',
21354 if(this.tabScrollable){
21361 cls: 'nav nav-tabs pull-right',
21372 cls: 'nav-tabs-custom',
21377 cls: 'tab-content no-padding',
21385 initEvents : function()
21387 //Roo.log('add add pane handler');
21388 this.on('addpane', this.onAddPane, this);
21391 * Updates the box title
21392 * @param {String} html to set the title to.
21394 setTitle : function(value)
21396 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21398 onAddPane : function(pane)
21400 this.panes.push(pane);
21401 //Roo.log('addpane');
21403 // tabs are rendere left to right..
21404 if(!this.showtabs){
21408 var ctr = this.el.select('.nav-tabs', true).first();
21411 var existing = ctr.select('.nav-tab',true);
21412 var qty = existing.getCount();;
21415 var tab = ctr.createChild({
21417 cls : 'nav-tab' + (qty ? '' : ' active'),
21425 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21428 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21430 pane.el.addClass('active');
21435 onTabClick : function(ev,un,ob,pane)
21437 //Roo.log('tab - prev default');
21438 ev.preventDefault();
21441 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21442 pane.tab.addClass('active');
21443 //Roo.log(pane.title);
21444 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21445 // technically we should have a deactivate event.. but maybe add later.
21446 // and it should not de-activate the selected tab...
21447 this.fireEvent('activatepane', pane);
21448 pane.el.addClass('active');
21449 pane.fireEvent('activate');
21454 getActivePane : function()
21457 Roo.each(this.panes, function(p) {
21458 if(p.el.hasClass('active')){
21479 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21481 * @class Roo.bootstrap.TabPane
21482 * @extends Roo.bootstrap.Component
21483 * Bootstrap TabPane class
21484 * @cfg {Boolean} active (false | true) Default false
21485 * @cfg {String} title title of panel
21489 * Create a new TabPane
21490 * @param {Object} config The config object
21493 Roo.bootstrap.dash.TabPane = function(config){
21494 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21500 * When a pane is activated
21501 * @param {Roo.bootstrap.dash.TabPane} pane
21508 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21513 // the tabBox that this is attached to.
21516 getAutoCreate : function()
21524 cfg.cls += ' active';
21529 initEvents : function()
21531 //Roo.log('trigger add pane handler');
21532 this.parent().fireEvent('addpane', this)
21536 * Updates the tab title
21537 * @param {String} html to set the title to.
21539 setTitle: function(str)
21545 this.tab.select('a', true).first().dom.innerHTML = str;
21562 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21565 * @class Roo.bootstrap.menu.Menu
21566 * @extends Roo.bootstrap.Component
21567 * Bootstrap Menu class - container for Menu
21568 * @cfg {String} html Text of the menu
21569 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21570 * @cfg {String} icon Font awesome icon
21571 * @cfg {String} pos Menu align to (top | bottom) default bottom
21575 * Create a new Menu
21576 * @param {Object} config The config object
21580 Roo.bootstrap.menu.Menu = function(config){
21581 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21585 * @event beforeshow
21586 * Fires before this menu is displayed
21587 * @param {Roo.bootstrap.menu.Menu} this
21591 * @event beforehide
21592 * Fires before this menu is hidden
21593 * @param {Roo.bootstrap.menu.Menu} this
21598 * Fires after this menu is displayed
21599 * @param {Roo.bootstrap.menu.Menu} this
21604 * Fires after this menu is hidden
21605 * @param {Roo.bootstrap.menu.Menu} this
21610 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21611 * @param {Roo.bootstrap.menu.Menu} this
21612 * @param {Roo.EventObject} e
21619 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21623 weight : 'default',
21628 getChildContainer : function() {
21629 if(this.isSubMenu){
21633 return this.el.select('ul.dropdown-menu', true).first();
21636 getAutoCreate : function()
21641 cls : 'roo-menu-text',
21649 cls : 'fa ' + this.icon
21660 cls : 'dropdown-button btn btn-' + this.weight,
21665 cls : 'dropdown-toggle btn btn-' + this.weight,
21675 cls : 'dropdown-menu'
21681 if(this.pos == 'top'){
21682 cfg.cls += ' dropup';
21685 if(this.isSubMenu){
21688 cls : 'dropdown-menu'
21695 onRender : function(ct, position)
21697 this.isSubMenu = ct.hasClass('dropdown-submenu');
21699 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21702 initEvents : function()
21704 if(this.isSubMenu){
21708 this.hidden = true;
21710 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21711 this.triggerEl.on('click', this.onTriggerPress, this);
21713 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21714 this.buttonEl.on('click', this.onClick, this);
21720 if(this.isSubMenu){
21724 return this.el.select('ul.dropdown-menu', true).first();
21727 onClick : function(e)
21729 this.fireEvent("click", this, e);
21732 onTriggerPress : function(e)
21734 if (this.isVisible()) {
21741 isVisible : function(){
21742 return !this.hidden;
21747 this.fireEvent("beforeshow", this);
21749 this.hidden = false;
21750 this.el.addClass('open');
21752 Roo.get(document).on("mouseup", this.onMouseUp, this);
21754 this.fireEvent("show", this);
21761 this.fireEvent("beforehide", this);
21763 this.hidden = true;
21764 this.el.removeClass('open');
21766 Roo.get(document).un("mouseup", this.onMouseUp);
21768 this.fireEvent("hide", this);
21771 onMouseUp : function()
21785 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21788 * @class Roo.bootstrap.menu.Item
21789 * @extends Roo.bootstrap.Component
21790 * Bootstrap MenuItem class
21791 * @cfg {Boolean} submenu (true | false) default false
21792 * @cfg {String} html text of the item
21793 * @cfg {String} href the link
21794 * @cfg {Boolean} disable (true | false) default false
21795 * @cfg {Boolean} preventDefault (true | false) default true
21796 * @cfg {String} icon Font awesome icon
21797 * @cfg {String} pos Submenu align to (left | right) default right
21801 * Create a new Item
21802 * @param {Object} config The config object
21806 Roo.bootstrap.menu.Item = function(config){
21807 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21811 * Fires when the mouse is hovering over this menu
21812 * @param {Roo.bootstrap.menu.Item} this
21813 * @param {Roo.EventObject} e
21818 * Fires when the mouse exits this menu
21819 * @param {Roo.bootstrap.menu.Item} this
21820 * @param {Roo.EventObject} e
21826 * The raw click event for the entire grid.
21827 * @param {Roo.EventObject} e
21833 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21838 preventDefault: true,
21843 getAutoCreate : function()
21848 cls : 'roo-menu-item-text',
21856 cls : 'fa ' + this.icon
21865 href : this.href || '#',
21872 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21876 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21878 if(this.pos == 'left'){
21879 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21886 initEvents : function()
21888 this.el.on('mouseover', this.onMouseOver, this);
21889 this.el.on('mouseout', this.onMouseOut, this);
21891 this.el.select('a', true).first().on('click', this.onClick, this);
21895 onClick : function(e)
21897 if(this.preventDefault){
21898 e.preventDefault();
21901 this.fireEvent("click", this, e);
21904 onMouseOver : function(e)
21906 if(this.submenu && this.pos == 'left'){
21907 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21910 this.fireEvent("mouseover", this, e);
21913 onMouseOut : function(e)
21915 this.fireEvent("mouseout", this, e);
21927 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21930 * @class Roo.bootstrap.menu.Separator
21931 * @extends Roo.bootstrap.Component
21932 * Bootstrap Separator class
21935 * Create a new Separator
21936 * @param {Object} config The config object
21940 Roo.bootstrap.menu.Separator = function(config){
21941 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21944 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21946 getAutoCreate : function(){
21967 * @class Roo.bootstrap.Tooltip
21968 * Bootstrap Tooltip class
21969 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21970 * to determine which dom element triggers the tooltip.
21972 * It needs to add support for additional attributes like tooltip-position
21975 * Create a new Toolti
21976 * @param {Object} config The config object
21979 Roo.bootstrap.Tooltip = function(config){
21980 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21983 Roo.apply(Roo.bootstrap.Tooltip, {
21985 * @function init initialize tooltip monitoring.
21989 currentTip : false,
21990 currentRegion : false,
21996 Roo.get(document).on('mouseover', this.enter ,this);
21997 Roo.get(document).on('mouseout', this.leave, this);
22000 this.currentTip = new Roo.bootstrap.Tooltip();
22003 enter : function(ev)
22005 var dom = ev.getTarget();
22007 //Roo.log(['enter',dom]);
22008 var el = Roo.fly(dom);
22009 if (this.currentEl) {
22011 //Roo.log(this.currentEl);
22012 //Roo.log(this.currentEl.contains(dom));
22013 if (this.currentEl == el) {
22016 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22024 if (this.currentTip.el) {
22025 this.currentTip.el.hide(); // force hiding...
22030 // you can not look for children, as if el is the body.. then everythign is the child..
22031 if (!el.attr('tooltip')) { //
22032 if (!el.select("[tooltip]").elements.length) {
22035 // is the mouse over this child...?
22036 bindEl = el.select("[tooltip]").first();
22037 var xy = ev.getXY();
22038 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22039 //Roo.log("not in region.");
22042 //Roo.log("child element over..");
22045 this.currentEl = bindEl;
22046 this.currentTip.bind(bindEl);
22047 this.currentRegion = Roo.lib.Region.getRegion(dom);
22048 this.currentTip.enter();
22051 leave : function(ev)
22053 var dom = ev.getTarget();
22054 //Roo.log(['leave',dom]);
22055 if (!this.currentEl) {
22060 if (dom != this.currentEl.dom) {
22063 var xy = ev.getXY();
22064 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22067 // only activate leave if mouse cursor is outside... bounding box..
22072 if (this.currentTip) {
22073 this.currentTip.leave();
22075 //Roo.log('clear currentEl');
22076 this.currentEl = false;
22081 'left' : ['r-l', [-2,0], 'right'],
22082 'right' : ['l-r', [2,0], 'left'],
22083 'bottom' : ['t-b', [0,2], 'top'],
22084 'top' : [ 'b-t', [0,-2], 'bottom']
22090 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22095 delay : null, // can be { show : 300 , hide: 500}
22099 hoverState : null, //???
22101 placement : 'bottom',
22103 getAutoCreate : function(){
22110 cls : 'tooltip-arrow'
22113 cls : 'tooltip-inner'
22120 bind : function(el)
22126 enter : function () {
22128 if (this.timeout != null) {
22129 clearTimeout(this.timeout);
22132 this.hoverState = 'in';
22133 //Roo.log("enter - show");
22134 if (!this.delay || !this.delay.show) {
22139 this.timeout = setTimeout(function () {
22140 if (_t.hoverState == 'in') {
22143 }, this.delay.show);
22147 clearTimeout(this.timeout);
22149 this.hoverState = 'out';
22150 if (!this.delay || !this.delay.hide) {
22156 this.timeout = setTimeout(function () {
22157 //Roo.log("leave - timeout");
22159 if (_t.hoverState == 'out') {
22161 Roo.bootstrap.Tooltip.currentEl = false;
22169 this.render(document.body);
22172 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22174 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22176 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22178 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22180 var placement = typeof this.placement == 'function' ?
22181 this.placement.call(this, this.el, on_el) :
22184 var autoToken = /\s?auto?\s?/i;
22185 var autoPlace = autoToken.test(placement);
22187 placement = placement.replace(autoToken, '') || 'top';
22191 //this.el.setXY([0,0]);
22193 //this.el.dom.style.display='block';
22194 this.el.addClass(placement);
22196 //this.el.appendTo(on_el);
22198 var p = this.getPosition();
22199 var box = this.el.getBox();
22204 var align = Roo.bootstrap.Tooltip.alignment[placement];
22205 this.el.alignTo(this.bindEl, align[0],align[1]);
22206 //var arrow = this.el.select('.arrow',true).first();
22207 //arrow.set(align[2],
22209 this.el.addClass('in fade');
22210 this.hoverState = null;
22212 if (this.el.hasClass('fade')) {
22223 //this.el.setXY([0,0]);
22224 this.el.removeClass('in');
22240 * @class Roo.bootstrap.LocationPicker
22241 * @extends Roo.bootstrap.Component
22242 * Bootstrap LocationPicker class
22243 * @cfg {Number} latitude Position when init default 0
22244 * @cfg {Number} longitude Position when init default 0
22245 * @cfg {Number} zoom default 15
22246 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22247 * @cfg {Boolean} mapTypeControl default false
22248 * @cfg {Boolean} disableDoubleClickZoom default false
22249 * @cfg {Boolean} scrollwheel default true
22250 * @cfg {Boolean} streetViewControl default false
22251 * @cfg {Number} radius default 0
22252 * @cfg {String} locationName
22253 * @cfg {Boolean} draggable default true
22254 * @cfg {Boolean} enableAutocomplete default false
22255 * @cfg {Boolean} enableReverseGeocode default true
22256 * @cfg {String} markerTitle
22259 * Create a new LocationPicker
22260 * @param {Object} config The config object
22264 Roo.bootstrap.LocationPicker = function(config){
22266 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22271 * Fires when the picker initialized.
22272 * @param {Roo.bootstrap.LocationPicker} this
22273 * @param {Google Location} location
22277 * @event positionchanged
22278 * Fires when the picker position changed.
22279 * @param {Roo.bootstrap.LocationPicker} this
22280 * @param {Google Location} location
22282 positionchanged : true,
22285 * Fires when the map resize.
22286 * @param {Roo.bootstrap.LocationPicker} this
22291 * Fires when the map show.
22292 * @param {Roo.bootstrap.LocationPicker} this
22297 * Fires when the map hide.
22298 * @param {Roo.bootstrap.LocationPicker} this
22303 * Fires when click the map.
22304 * @param {Roo.bootstrap.LocationPicker} this
22305 * @param {Map event} e
22309 * @event mapRightClick
22310 * Fires when right click the map.
22311 * @param {Roo.bootstrap.LocationPicker} this
22312 * @param {Map event} e
22314 mapRightClick : true,
22316 * @event markerClick
22317 * Fires when click the marker.
22318 * @param {Roo.bootstrap.LocationPicker} this
22319 * @param {Map event} e
22321 markerClick : true,
22323 * @event markerRightClick
22324 * Fires when right click the marker.
22325 * @param {Roo.bootstrap.LocationPicker} this
22326 * @param {Map event} e
22328 markerRightClick : true,
22330 * @event OverlayViewDraw
22331 * Fires when OverlayView Draw
22332 * @param {Roo.bootstrap.LocationPicker} this
22334 OverlayViewDraw : true,
22336 * @event OverlayViewOnAdd
22337 * Fires when OverlayView Draw
22338 * @param {Roo.bootstrap.LocationPicker} this
22340 OverlayViewOnAdd : true,
22342 * @event OverlayViewOnRemove
22343 * Fires when OverlayView Draw
22344 * @param {Roo.bootstrap.LocationPicker} this
22346 OverlayViewOnRemove : true,
22348 * @event OverlayViewShow
22349 * Fires when OverlayView Draw
22350 * @param {Roo.bootstrap.LocationPicker} this
22351 * @param {Pixel} cpx
22353 OverlayViewShow : true,
22355 * @event OverlayViewHide
22356 * Fires when OverlayView Draw
22357 * @param {Roo.bootstrap.LocationPicker} this
22359 OverlayViewHide : true
22364 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22366 gMapContext: false,
22372 mapTypeControl: false,
22373 disableDoubleClickZoom: false,
22375 streetViewControl: false,
22379 enableAutocomplete: false,
22380 enableReverseGeocode: true,
22383 getAutoCreate: function()
22388 cls: 'roo-location-picker'
22394 initEvents: function(ct, position)
22396 if(!this.el.getWidth() || this.isApplied()){
22400 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22405 initial: function()
22407 if(!this.mapTypeId){
22408 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22411 this.gMapContext = this.GMapContext();
22413 this.initOverlayView();
22415 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22419 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22420 _this.setPosition(_this.gMapContext.marker.position);
22423 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22424 _this.fireEvent('mapClick', this, event);
22428 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22429 _this.fireEvent('mapRightClick', this, event);
22433 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22434 _this.fireEvent('markerClick', this, event);
22438 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22439 _this.fireEvent('markerRightClick', this, event);
22443 this.setPosition(this.gMapContext.location);
22445 this.fireEvent('initial', this, this.gMapContext.location);
22448 initOverlayView: function()
22452 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22456 _this.fireEvent('OverlayViewDraw', _this);
22461 _this.fireEvent('OverlayViewOnAdd', _this);
22464 onRemove: function()
22466 _this.fireEvent('OverlayViewOnRemove', _this);
22469 show: function(cpx)
22471 _this.fireEvent('OverlayViewShow', _this, cpx);
22476 _this.fireEvent('OverlayViewHide', _this);
22482 fromLatLngToContainerPixel: function(event)
22484 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22487 isApplied: function()
22489 return this.getGmapContext() == false ? false : true;
22492 getGmapContext: function()
22494 return this.gMapContext
22497 GMapContext: function()
22499 var position = new google.maps.LatLng(this.latitude, this.longitude);
22501 var _map = new google.maps.Map(this.el.dom, {
22504 mapTypeId: this.mapTypeId,
22505 mapTypeControl: this.mapTypeControl,
22506 disableDoubleClickZoom: this.disableDoubleClickZoom,
22507 scrollwheel: this.scrollwheel,
22508 streetViewControl: this.streetViewControl,
22509 locationName: this.locationName,
22510 draggable: this.draggable,
22511 enableAutocomplete: this.enableAutocomplete,
22512 enableReverseGeocode: this.enableReverseGeocode
22515 var _marker = new google.maps.Marker({
22516 position: position,
22518 title: this.markerTitle,
22519 draggable: this.draggable
22526 location: position,
22527 radius: this.radius,
22528 locationName: this.locationName,
22529 addressComponents: {
22530 formatted_address: null,
22531 addressLine1: null,
22532 addressLine2: null,
22534 streetNumber: null,
22538 stateOrProvince: null
22541 domContainer: this.el.dom,
22542 geodecoder: new google.maps.Geocoder()
22546 drawCircle: function(center, radius, options)
22548 if (this.gMapContext.circle != null) {
22549 this.gMapContext.circle.setMap(null);
22553 options = Roo.apply({}, options, {
22554 strokeColor: "#0000FF",
22555 strokeOpacity: .35,
22557 fillColor: "#0000FF",
22561 options.map = this.gMapContext.map;
22562 options.radius = radius;
22563 options.center = center;
22564 this.gMapContext.circle = new google.maps.Circle(options);
22565 return this.gMapContext.circle;
22571 setPosition: function(location)
22573 this.gMapContext.location = location;
22574 this.gMapContext.marker.setPosition(location);
22575 this.gMapContext.map.panTo(location);
22576 this.drawCircle(location, this.gMapContext.radius, {});
22580 if (this.gMapContext.settings.enableReverseGeocode) {
22581 this.gMapContext.geodecoder.geocode({
22582 latLng: this.gMapContext.location
22583 }, function(results, status) {
22585 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22586 _this.gMapContext.locationName = results[0].formatted_address;
22587 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22589 _this.fireEvent('positionchanged', this, location);
22596 this.fireEvent('positionchanged', this, location);
22601 google.maps.event.trigger(this.gMapContext.map, "resize");
22603 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22605 this.fireEvent('resize', this);
22608 setPositionByLatLng: function(latitude, longitude)
22610 this.setPosition(new google.maps.LatLng(latitude, longitude));
22613 getCurrentPosition: function()
22616 latitude: this.gMapContext.location.lat(),
22617 longitude: this.gMapContext.location.lng()
22621 getAddressName: function()
22623 return this.gMapContext.locationName;
22626 getAddressComponents: function()
22628 return this.gMapContext.addressComponents;
22631 address_component_from_google_geocode: function(address_components)
22635 for (var i = 0; i < address_components.length; i++) {
22636 var component = address_components[i];
22637 if (component.types.indexOf("postal_code") >= 0) {
22638 result.postalCode = component.short_name;
22639 } else if (component.types.indexOf("street_number") >= 0) {
22640 result.streetNumber = component.short_name;
22641 } else if (component.types.indexOf("route") >= 0) {
22642 result.streetName = component.short_name;
22643 } else if (component.types.indexOf("neighborhood") >= 0) {
22644 result.city = component.short_name;
22645 } else if (component.types.indexOf("locality") >= 0) {
22646 result.city = component.short_name;
22647 } else if (component.types.indexOf("sublocality") >= 0) {
22648 result.district = component.short_name;
22649 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22650 result.stateOrProvince = component.short_name;
22651 } else if (component.types.indexOf("country") >= 0) {
22652 result.country = component.short_name;
22656 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22657 result.addressLine2 = "";
22661 setZoomLevel: function(zoom)
22663 this.gMapContext.map.setZoom(zoom);
22676 this.fireEvent('show', this);
22687 this.fireEvent('hide', this);
22692 Roo.apply(Roo.bootstrap.LocationPicker, {
22694 OverlayView : function(map, options)
22696 options = options || {};
22710 * @class Roo.bootstrap.Alert
22711 * @extends Roo.bootstrap.Component
22712 * Bootstrap Alert class
22713 * @cfg {String} title The title of alert
22714 * @cfg {String} html The content of alert
22715 * @cfg {String} weight ( success | info | warning | danger )
22716 * @cfg {String} faicon font-awesomeicon
22719 * Create a new alert
22720 * @param {Object} config The config object
22724 Roo.bootstrap.Alert = function(config){
22725 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22729 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22736 getAutoCreate : function()
22745 cls : 'roo-alert-icon'
22750 cls : 'roo-alert-title',
22755 cls : 'roo-alert-text',
22762 cfg.cn[0].cls += ' fa ' + this.faicon;
22766 cfg.cls += ' alert-' + this.weight;
22772 initEvents: function()
22774 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22777 setTitle : function(str)
22779 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22782 setText : function(str)
22784 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22787 setWeight : function(weight)
22790 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22793 this.weight = weight;
22795 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22798 setIcon : function(icon)
22801 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22806 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);