4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
232 addxtypeChild : function (tree, cntr)
234 Roo.debug && Roo.log('addxtypeChild:' + cntr);
236 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
240 (typeof(tree['flexy:foreach']) != 'undefined');
244 skip_children = false;
245 // render the element if it's not BODY.
246 if (tree.xtype != 'Body') {
248 cn = Roo.factory(tree);
250 cn.parentType = this.xtype; //??
251 cn.parentId = this.id;
253 var build_from_html = Roo.XComponent.build_from_html;
256 // does the container contain child eleemnts with 'xtype' attributes.
257 // that match this xtype..
258 // note - when we render we create these as well..
259 // so we should check to see if body has xtype set.
260 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
262 var self_cntr_el = Roo.get(this[cntr](false));
263 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
265 Roo.log(Roo.XComponent.build_from_html);
266 Roo.log("got echild:");
269 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
270 // and are not displayed -this causes this to use up the wrong element when matching.
271 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
274 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
275 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
281 //echild.dom.removeAttribute('xtype');
283 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
284 Roo.debug && Roo.log(self_cntr_el);
285 Roo.debug && Roo.log(echild);
286 Roo.debug && Roo.log(cn);
292 // if object has flexy:if - then it may or may not be rendered.
293 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
294 // skip a flexy if element.
295 Roo.debug && Roo.log('skipping render');
296 Roo.debug && Roo.log(tree);
298 Roo.debug && Roo.log('skipping all children');
299 skip_children = true;
304 // actually if flexy:foreach is found, we really want to create
305 // multiple copies here...
307 //Roo.log(this[cntr]());
308 cn.render(this[cntr](true));
310 // then add the element..
318 if (typeof (tree.menu) != 'undefined') {
319 tree.menu.parentType = cn.xtype;
320 tree.menu.triggerEl = cn.el;
321 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
325 if (!tree.items || !tree.items.length) {
329 var items = tree.items;
332 //Roo.log(items.length);
334 if (!skip_children) {
335 for(var i =0;i < items.length;i++) {
336 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
342 this.fireEvent('childrenrendered', this);
358 * @class Roo.bootstrap.Body
359 * @extends Roo.bootstrap.Component
360 * Bootstrap Body class
364 * @param {Object} config The config object
367 Roo.bootstrap.Body = function(config){
368 Roo.bootstrap.Body.superclass.constructor.call(this, config);
369 this.el = Roo.get(document.body);
370 if (this.cls && this.cls.length) {
371 Roo.get(document.body).addClass(this.cls);
375 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
380 onRender : function(ct, position)
382 /* Roo.log("Roo.bootstrap.Body - onRender");
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
404 * @class Roo.bootstrap.ButtonGroup
405 * @extends Roo.bootstrap.Component
406 * Bootstrap ButtonGroup class
407 * @cfg {String} size lg | sm | xs (default empty normal)
408 * @cfg {String} align vertical | justified (default none)
409 * @cfg {String} direction up | down (default down)
410 * @cfg {Boolean} toolbar false | true
411 * @cfg {Boolean} btn true | false
416 * @param {Object} config The config object
419 Roo.bootstrap.ButtonGroup = function(config){
420 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
423 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
431 getAutoCreate : function(){
437 cfg.html = this.html || cfg.html;
448 if (['vertical','justified'].indexOf(this.align)!==-1) {
449 cfg.cls = 'btn-group-' + this.align;
451 if (this.align == 'justified') {
452 console.log(this.items);
456 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
457 cfg.cls += ' btn-group-' + this.size;
460 if (this.direction == 'up') {
461 cfg.cls += ' dropup' ;
477 * @class Roo.bootstrap.Button
478 * @extends Roo.bootstrap.Component
479 * Bootstrap Button class
480 * @cfg {String} html The button content
481 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
482 * @cfg {String} size ( lg | sm | xs)
483 * @cfg {String} tag ( a | input | submit)
484 * @cfg {String} href empty or href
485 * @cfg {Boolean} disabled default false;
486 * @cfg {Boolean} isClose default false;
487 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
488 * @cfg {String} badge text for badge
489 * @cfg {String} theme default
490 * @cfg {Boolean} inverse
491 * @cfg {Boolean} toggle
492 * @cfg {String} ontext text for on toggle state
493 * @cfg {String} offtext text for off toggle state
494 * @cfg {Boolean} defaulton
495 * @cfg {Boolean} preventDefault default true
496 * @cfg {Boolean} removeClass remove the standard class..
497 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
500 * Create a new button
501 * @param {Object} config The config object
505 Roo.bootstrap.Button = function(config){
506 Roo.bootstrap.Button.superclass.constructor.call(this, config);
511 * When a butotn is pressed
512 * @param {Roo.bootstrap.Button} this
513 * @param {Roo.EventObject} e
518 * After the button has been toggles
519 * @param {Roo.EventObject} e
520 * @param {boolean} pressed (also available as button.pressed)
526 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
544 preventDefault: true,
553 getAutoCreate : function(){
561 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
562 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
567 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
569 if (this.toggle == true) {
572 cls: 'slider-frame roo-button',
577 'data-off-text':'OFF',
578 cls: 'slider-button',
584 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585 cfg.cls += ' '+this.weight;
594 cfg["aria-hidden"] = true;
596 cfg.html = "×";
602 if (this.theme==='default') {
603 cfg.cls = 'btn roo-button';
605 //if (this.parentType != 'Navbar') {
606 this.weight = this.weight.length ? this.weight : 'default';
608 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
610 cfg.cls += ' btn-' + this.weight;
612 } else if (this.theme==='glow') {
615 cfg.cls = 'btn-glow roo-button';
617 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
619 cfg.cls += ' ' + this.weight;
625 this.cls += ' inverse';
630 cfg.cls += ' active';
634 cfg.disabled = 'disabled';
638 Roo.log('changing to ul' );
640 this.glyphicon = 'caret';
643 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
645 //gsRoo.log(this.parentType);
646 if (this.parentType === 'Navbar' && !this.parent().bar) {
647 Roo.log('changing to li?');
656 href : this.href || '#'
659 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
660 cfg.cls += ' dropdown';
667 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
669 if (this.glyphicon) {
670 cfg.html = ' ' + cfg.html;
675 cls: 'glyphicon glyphicon-' + this.glyphicon
685 // cfg.cls='btn roo-button';
689 var value = cfg.html;
694 cls: 'glyphicon glyphicon-' + this.glyphicon,
713 cfg.cls += ' dropdown';
714 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
717 if (cfg.tag !== 'a' && this.href !== '') {
718 throw "Tag must be a to set href.";
719 } else if (this.href.length > 0) {
720 cfg.href = this.href;
723 if(this.removeClass){
728 cfg.target = this.target;
733 initEvents: function() {
734 // Roo.log('init events?');
735 // Roo.log(this.el.dom);
738 if (typeof (this.menu) != 'undefined') {
739 this.menu.parentType = this.xtype;
740 this.menu.triggerEl = this.el;
741 this.addxtype(Roo.apply({}, this.menu));
745 if (this.el.hasClass('roo-button')) {
746 this.el.on('click', this.onClick, this);
748 this.el.select('.roo-button').on('click', this.onClick, this);
751 if(this.removeClass){
752 this.el.on('click', this.onClick, this);
755 this.el.enableDisplayMode();
758 onClick : function(e)
765 Roo.log('button on click ');
766 if(this.preventDefault){
769 if (this.pressed === true || this.pressed === false) {
770 this.pressed = !this.pressed;
771 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
772 this.fireEvent('toggle', this, e, this.pressed);
776 this.fireEvent('click', this, e);
780 * Enables this button
784 this.disabled = false;
785 this.el.removeClass('disabled');
789 * Disable this button
793 this.disabled = true;
794 this.el.addClass('disabled');
797 * sets the active state on/off,
798 * @param {Boolean} state (optional) Force a particular state
800 setActive : function(v) {
802 this.el[v ? 'addClass' : 'removeClass']('active');
805 * toggles the current active state
807 toggleActive : function()
809 var active = this.el.hasClass('active');
810 this.setActive(!active);
814 setText : function(str)
816 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
820 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
843 * @class Roo.bootstrap.Column
844 * @extends Roo.bootstrap.Component
845 * Bootstrap Column class
846 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
847 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
848 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
849 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
850 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
851 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
852 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
853 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
856 * @cfg {Boolean} hidden (true|false) hide the element
857 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
858 * @cfg {String} fa (ban|check|...) font awesome icon
859 * @cfg {Number} fasize (1|2|....) font awsome size
861 * @cfg {String} icon (info-sign|check|...) glyphicon name
863 * @cfg {String} html content of column.
866 * Create a new Column
867 * @param {Object} config The config object
870 Roo.bootstrap.Column = function(config){
871 Roo.bootstrap.Column.superclass.constructor.call(this, config);
874 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
892 getAutoCreate : function(){
893 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
901 ['xs','sm','md','lg'].map(function(size){
902 //Roo.log( size + ':' + settings[size]);
904 if (settings[size+'off'] !== false) {
905 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
908 if (settings[size] === false) {
911 Roo.log(settings[size]);
912 if (!settings[size]) { // 0 = hidden
913 cfg.cls += ' hidden-' + size;
916 cfg.cls += ' col-' + size + '-' + settings[size];
921 cfg.cls += ' hidden';
924 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
925 cfg.cls +=' alert alert-' + this.alert;
929 if (this.html.length) {
930 cfg.html = this.html;
934 if (this.fasize > 1) {
935 fasize = ' fa-' + this.fasize + 'x';
937 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
942 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
961 * @class Roo.bootstrap.Container
962 * @extends Roo.bootstrap.Component
963 * Bootstrap Container class
964 * @cfg {Boolean} jumbotron is it a jumbotron element
965 * @cfg {String} html content of element
966 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
967 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
968 * @cfg {String} header content of header (for panel)
969 * @cfg {String} footer content of footer (for panel)
970 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
971 * @cfg {String} tag (header|aside|section) type of HTML tag.
972 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
973 * @cfg {String} fa (ban|check|...) font awesome icon
974 * @cfg {String} icon (info-sign|check|...) glyphicon name
975 * @cfg {Boolean} hidden (true|false) hide the element
979 * Create a new Container
980 * @param {Object} config The config object
983 Roo.bootstrap.Container = function(config){
984 Roo.bootstrap.Container.superclass.constructor.call(this, config);
987 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1001 getChildContainer : function() {
1007 if (this.panel.length) {
1008 return this.el.select('.panel-body',true).first();
1015 getAutoCreate : function(){
1018 tag : this.tag || 'div',
1022 if (this.jumbotron) {
1023 cfg.cls = 'jumbotron';
1028 // - this is applied by the parent..
1030 // cfg.cls = this.cls + '';
1033 if (this.sticky.length) {
1035 var bd = Roo.get(document.body);
1036 if (!bd.hasClass('bootstrap-sticky')) {
1037 bd.addClass('bootstrap-sticky');
1038 Roo.select('html',true).setStyle('height', '100%');
1041 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1045 if (this.well.length) {
1046 switch (this.well) {
1049 cfg.cls +=' well well-' +this.well;
1058 cfg.cls += ' hidden';
1062 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1063 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.panel.length) {
1069 cfg.cls += ' panel panel-' + this.panel;
1071 if (this.header.length) {
1074 cls : 'panel-heading',
1077 cls : 'panel-title',
1090 if (this.footer.length) {
1092 cls : 'panel-footer',
1101 body.html = this.html || cfg.html;
1102 // prefix with the icons..
1104 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1107 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1112 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1113 cfg.cls = 'container';
1119 titleEl : function()
1121 if(!this.el || !this.panel.length || !this.header.length){
1125 return this.el.select('.panel-title',true).first();
1128 setTitle : function(v)
1130 var titleEl = this.titleEl();
1136 titleEl.dom.innerHTML = v;
1139 getTitle : function()
1142 var titleEl = this.titleEl();
1148 return titleEl.dom.innerHTML;
1152 this.el.removeClass('hidden');
1155 if (!this.el.hasClass('hidden')) {
1156 this.el.addClass('hidden');
1172 * @class Roo.bootstrap.Img
1173 * @extends Roo.bootstrap.Component
1174 * Bootstrap Img class
1175 * @cfg {Boolean} imgResponsive false | true
1176 * @cfg {String} border rounded | circle | thumbnail
1177 * @cfg {String} src image source
1178 * @cfg {String} alt image alternative text
1179 * @cfg {String} href a tag href
1180 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1183 * Create a new Input
1184 * @param {Object} config The config object
1187 Roo.bootstrap.Img = function(config){
1188 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1194 * The img click event for the img.
1195 * @param {Roo.EventObject} e
1201 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1203 imgResponsive: true,
1209 getAutoCreate : function(){
1213 cls: (this.imgResponsive) ? 'img-responsive' : '',
1217 cfg.html = this.html || cfg.html;
1219 cfg.src = this.src || cfg.src;
1221 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1222 cfg.cls += ' img-' + this.border;
1239 a.target = this.target;
1245 return (this.href) ? a : cfg;
1248 initEvents: function() {
1251 this.el.on('click', this.onClick, this);
1255 onClick : function(e)
1257 Roo.log('img onclick');
1258 this.fireEvent('click', this, e);
1272 * @class Roo.bootstrap.Link
1273 * @extends Roo.bootstrap.Component
1274 * Bootstrap Link Class
1275 * @cfg {String} alt image alternative text
1276 * @cfg {String} href a tag href
1277 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1278 * @cfg {String} html the content of the link.
1279 * @cfg {String} anchor name for the anchor link
1281 * @cfg {Boolean} preventDefault (true | false) default false
1285 * Create a new Input
1286 * @param {Object} config The config object
1289 Roo.bootstrap.Link = function(config){
1290 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1296 * The img click event for the img.
1297 * @param {Roo.EventObject} e
1303 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1307 preventDefault: false,
1311 getAutoCreate : function()
1317 // anchor's do not require html/href...
1318 if (this.anchor === false) {
1319 cfg.html = this.html || 'html-missing';
1320 cfg.href = this.href || '#';
1322 cfg.name = this.anchor;
1323 if (this.html !== false) {
1324 cfg.html = this.html;
1326 if (this.href !== false) {
1327 cfg.href = this.href;
1331 if(this.alt !== false){
1336 if(this.target !== false) {
1337 cfg.target = this.target;
1343 initEvents: function() {
1345 if(!this.href || this.preventDefault){
1346 this.el.on('click', this.onClick, this);
1350 onClick : function(e)
1352 if(this.preventDefault){
1355 //Roo.log('img onclick');
1356 this.fireEvent('click', this, e);
1369 * @class Roo.bootstrap.Header
1370 * @extends Roo.bootstrap.Component
1371 * Bootstrap Header class
1372 * @cfg {String} html content of header
1373 * @cfg {Number} level (1|2|3|4|5|6) default 1
1376 * Create a new Header
1377 * @param {Object} config The config object
1381 Roo.bootstrap.Header = function(config){
1382 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1385 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1393 getAutoCreate : function(){
1398 tag: 'h' + (1 *this.level),
1399 html: this.html || ''
1411 * Ext JS Library 1.1.1
1412 * Copyright(c) 2006-2007, Ext JS, LLC.
1414 * Originally Released Under LGPL - original licence link has changed is not relivant.
1417 * <script type="text/javascript">
1421 * @class Roo.bootstrap.MenuMgr
1422 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1425 Roo.bootstrap.MenuMgr = function(){
1426 var menus, active, groups = {}, attached = false, lastShow = new Date();
1428 // private - called when first menu is created
1431 active = new Roo.util.MixedCollection();
1432 Roo.get(document).addKeyListener(27, function(){
1433 if(active.length > 0){
1441 if(active && active.length > 0){
1442 var c = active.clone();
1452 if(active.length < 1){
1453 Roo.get(document).un("mouseup", onMouseDown);
1461 var last = active.last();
1462 lastShow = new Date();
1465 Roo.get(document).on("mouseup", onMouseDown);
1470 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1471 m.parentMenu.activeChild = m;
1472 }else if(last && last.isVisible()){
1473 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1478 function onBeforeHide(m){
1480 m.activeChild.hide();
1482 if(m.autoHideTimer){
1483 clearTimeout(m.autoHideTimer);
1484 delete m.autoHideTimer;
1489 function onBeforeShow(m){
1490 var pm = m.parentMenu;
1491 if(!pm && !m.allowOtherMenus){
1493 }else if(pm && pm.activeChild && active != m){
1494 pm.activeChild.hide();
1499 function onMouseDown(e){
1500 Roo.log("on MouseDown");
1501 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1509 function onBeforeCheck(mi, state){
1511 var g = groups[mi.group];
1512 for(var i = 0, l = g.length; i < l; i++){
1514 g[i].setChecked(false);
1523 * Hides all menus that are currently visible
1525 hideAll : function(){
1530 register : function(menu){
1534 menus[menu.id] = menu;
1535 menu.on("beforehide", onBeforeHide);
1536 menu.on("hide", onHide);
1537 menu.on("beforeshow", onBeforeShow);
1538 menu.on("show", onShow);
1540 if(g && menu.events["checkchange"]){
1544 groups[g].push(menu);
1545 menu.on("checkchange", onCheck);
1550 * Returns a {@link Roo.menu.Menu} object
1551 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1552 * be used to generate and return a new Menu instance.
1554 get : function(menu){
1555 if(typeof menu == "string"){ // menu id
1557 }else if(menu.events){ // menu instance
1560 /*else if(typeof menu.length == 'number'){ // array of menu items?
1561 return new Roo.bootstrap.Menu({items:menu});
1562 }else{ // otherwise, must be a config
1563 return new Roo.bootstrap.Menu(menu);
1570 unregister : function(menu){
1571 delete menus[menu.id];
1572 menu.un("beforehide", onBeforeHide);
1573 menu.un("hide", onHide);
1574 menu.un("beforeshow", onBeforeShow);
1575 menu.un("show", onShow);
1577 if(g && menu.events["checkchange"]){
1578 groups[g].remove(menu);
1579 menu.un("checkchange", onCheck);
1584 registerCheckable : function(menuItem){
1585 var g = menuItem.group;
1590 groups[g].push(menuItem);
1591 menuItem.on("beforecheckchange", onBeforeCheck);
1596 unregisterCheckable : function(menuItem){
1597 var g = menuItem.group;
1599 groups[g].remove(menuItem);
1600 menuItem.un("beforecheckchange", onBeforeCheck);
1612 * @class Roo.bootstrap.Menu
1613 * @extends Roo.bootstrap.Component
1614 * Bootstrap Menu class - container for MenuItems
1615 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1619 * @param {Object} config The config object
1623 Roo.bootstrap.Menu = function(config){
1624 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1625 if (this.registerMenu) {
1626 Roo.bootstrap.MenuMgr.register(this);
1631 * Fires before this menu is displayed
1632 * @param {Roo.menu.Menu} this
1637 * Fires before this menu is hidden
1638 * @param {Roo.menu.Menu} this
1643 * Fires after this menu is displayed
1644 * @param {Roo.menu.Menu} this
1649 * Fires after this menu is hidden
1650 * @param {Roo.menu.Menu} this
1655 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1656 * @param {Roo.menu.Menu} this
1657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658 * @param {Roo.EventObject} e
1663 * Fires when the mouse is hovering over this menu
1664 * @param {Roo.menu.Menu} this
1665 * @param {Roo.EventObject} e
1666 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1671 * Fires when the mouse exits this menu
1672 * @param {Roo.menu.Menu} this
1673 * @param {Roo.EventObject} e
1674 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1679 * Fires when a menu item contained in this menu is clicked
1680 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1681 * @param {Roo.EventObject} e
1685 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1688 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1692 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1695 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1697 registerMenu : true,
1699 menuItems :false, // stores the menu items..
1705 getChildContainer : function() {
1709 getAutoCreate : function(){
1711 //if (['right'].indexOf(this.align)!==-1) {
1712 // cfg.cn[1].cls += ' pull-right'
1718 cls : 'dropdown-menu' ,
1719 style : 'z-index:1000'
1723 if (this.type === 'submenu') {
1724 cfg.cls = 'submenu active';
1726 if (this.type === 'treeview') {
1727 cfg.cls = 'treeview-menu';
1732 initEvents : function() {
1734 // Roo.log("ADD event");
1735 // Roo.log(this.triggerEl.dom);
1736 this.triggerEl.on('click', this.onTriggerPress, this);
1737 this.triggerEl.addClass('dropdown-toggle');
1738 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1740 this.el.on("mouseover", this.onMouseOver, this);
1741 this.el.on("mouseout", this.onMouseOut, this);
1745 findTargetItem : function(e){
1746 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1750 //Roo.log(t); Roo.log(t.id);
1752 //Roo.log(this.menuitems);
1753 return this.menuitems.get(t.id);
1755 //return this.items.get(t.menuItemId);
1760 onClick : function(e){
1761 Roo.log("menu.onClick");
1762 var t = this.findTargetItem(e);
1763 if(!t || t.isContainer){
1768 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1769 if(t == this.activeItem && t.shouldDeactivate(e)){
1770 this.activeItem.deactivate();
1771 delete this.activeItem;
1775 this.setActiveItem(t, true);
1783 Roo.log('pass click event');
1787 this.fireEvent("click", this, t, e);
1791 onMouseOver : function(e){
1792 var t = this.findTargetItem(e);
1795 // if(t.canActivate && !t.disabled){
1796 // this.setActiveItem(t, true);
1800 this.fireEvent("mouseover", this, e, t);
1802 isVisible : function(){
1803 return !this.hidden;
1805 onMouseOut : function(e){
1806 var t = this.findTargetItem(e);
1809 // if(t == this.activeItem && t.shouldDeactivate(e)){
1810 // this.activeItem.deactivate();
1811 // delete this.activeItem;
1814 this.fireEvent("mouseout", this, e, t);
1819 * Displays this menu relative to another element
1820 * @param {String/HTMLElement/Roo.Element} element The element to align to
1821 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1822 * the element (defaults to this.defaultAlign)
1823 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1825 show : function(el, pos, parentMenu){
1826 this.parentMenu = parentMenu;
1830 this.fireEvent("beforeshow", this);
1831 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1834 * Displays this menu at a specific xy position
1835 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1836 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1838 showAt : function(xy, parentMenu, /* private: */_e){
1839 this.parentMenu = parentMenu;
1844 this.fireEvent("beforeshow", this);
1845 //xy = this.el.adjustForConstraints(xy);
1849 this.hideMenuItems();
1850 this.hidden = false;
1851 this.triggerEl.addClass('open');
1853 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1854 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1859 this.fireEvent("show", this);
1865 this.doFocus.defer(50, this);
1869 doFocus : function(){
1871 this.focusEl.focus();
1876 * Hides this menu and optionally all parent menus
1877 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1879 hide : function(deep){
1881 this.hideMenuItems();
1882 if(this.el && this.isVisible()){
1883 this.fireEvent("beforehide", this);
1884 if(this.activeItem){
1885 this.activeItem.deactivate();
1886 this.activeItem = null;
1888 this.triggerEl.removeClass('open');;
1890 this.fireEvent("hide", this);
1892 if(deep === true && this.parentMenu){
1893 this.parentMenu.hide(true);
1897 onTriggerPress : function(e)
1900 Roo.log('trigger press');
1901 //Roo.log(e.getTarget());
1902 // Roo.log(this.triggerEl.dom);
1903 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1906 if (this.isVisible()) {
1910 this.show(this.triggerEl, false, false);
1919 hideMenuItems : function()
1921 //$(backdrop).remove()
1922 Roo.select('.open',true).each(function(aa) {
1924 aa.removeClass('open');
1925 //var parent = getParent($(this))
1926 //var relatedTarget = { relatedTarget: this }
1928 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1929 //if (e.isDefaultPrevented()) return
1930 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1933 addxtypeChild : function (tree, cntr) {
1934 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1936 this.menuitems.add(comp);
1957 * @class Roo.bootstrap.MenuItem
1958 * @extends Roo.bootstrap.Component
1959 * Bootstrap MenuItem class
1960 * @cfg {String} html the menu label
1961 * @cfg {String} href the link
1962 * @cfg {Boolean} preventDefault (true | false) default true
1963 * @cfg {Boolean} isContainer (true | false) default false
1967 * Create a new MenuItem
1968 * @param {Object} config The config object
1972 Roo.bootstrap.MenuItem = function(config){
1973 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1978 * The raw click event for the entire grid.
1979 * @param {Roo.bootstrap.MenuItem} this
1980 * @param {Roo.EventObject} e
1986 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1990 preventDefault: true,
1991 isContainer : false,
1993 getAutoCreate : function(){
1995 if(this.isContainer){
1998 cls: 'dropdown-menu-item'
2004 cls: 'dropdown-menu-item',
2013 if (this.parent().type == 'treeview') {
2014 cfg.cls = 'treeview-menu';
2017 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2018 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2022 initEvents: function() {
2024 //this.el.select('a').on('click', this.onClick, this);
2027 onClick : function(e)
2029 Roo.log('item on click ');
2030 //if(this.preventDefault){
2031 // e.preventDefault();
2033 //this.parent().hideMenuItems();
2035 this.fireEvent('click', this, e);
2054 * @class Roo.bootstrap.MenuSeparator
2055 * @extends Roo.bootstrap.Component
2056 * Bootstrap MenuSeparator class
2059 * Create a new MenuItem
2060 * @param {Object} config The config object
2064 Roo.bootstrap.MenuSeparator = function(config){
2065 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2068 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2070 getAutoCreate : function(){
2089 * @class Roo.bootstrap.Modal
2090 * @extends Roo.bootstrap.Component
2091 * Bootstrap Modal class
2092 * @cfg {String} title Title of dialog
2093 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2094 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2095 * @cfg {Boolean} specificTitle default false
2096 * @cfg {Array} buttons Array of buttons or standard button set..
2097 * @cfg {String} buttonPosition (left|right|center) default right
2098 * @cfg {Boolean} animate default true
2099 * @cfg {Boolean} allow_close default true
2102 * Create a new Modal Dialog
2103 * @param {Object} config The config object
2106 Roo.bootstrap.Modal = function(config){
2107 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2112 * The raw btnclick event for the button
2113 * @param {Roo.EventObject} e
2117 this.buttons = this.buttons || [];
2120 this.tmpl = Roo.factory(this.tmpl);
2125 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2127 title : 'test dialog',
2137 specificTitle: false,
2139 buttonPosition: 'right',
2153 onRender : function(ct, position)
2155 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2158 var cfg = Roo.apply({}, this.getAutoCreate());
2161 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2163 //if (!cfg.name.length) {
2167 cfg.cls += ' ' + this.cls;
2170 cfg.style = this.style;
2172 this.el = Roo.get(document.body).createChild(cfg, position);
2174 //var type = this.el.dom.type;
2179 if(this.tabIndex !== undefined){
2180 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2184 this.bodyEl = this.el.select('.modal-body',true).first();
2185 this.closeEl = this.el.select('.modal-header .close', true).first();
2186 this.footerEl = this.el.select('.modal-footer',true).first();
2187 this.titleEl = this.el.select('.modal-title',true).first();
2191 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2192 this.maskEl.enableDisplayMode("block");
2194 //this.el.addClass("x-dlg-modal");
2196 if (this.buttons.length) {
2197 Roo.each(this.buttons, function(bb) {
2198 b = Roo.apply({}, bb);
2199 b.xns = b.xns || Roo.bootstrap;
2200 b.xtype = b.xtype || 'Button';
2201 if (typeof(b.listeners) == 'undefined') {
2202 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2205 var btn = Roo.factory(b);
2207 btn.onRender(this.el.select('.modal-footer div').first());
2211 // render the children.
2214 if(typeof(this.items) != 'undefined'){
2215 var items = this.items;
2218 for(var i =0;i < items.length;i++) {
2219 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2223 this.items = nitems;
2225 // where are these used - they used to be body/close/footer
2229 //this.el.addClass([this.fieldClass, this.cls]);
2232 getAutoCreate : function(){
2237 html : this.html || ''
2242 cls : 'modal-title',
2246 if(this.specificTitle){
2252 if (this.allow_close) {
2263 style : 'display: none',
2266 cls: "modal-dialog",
2269 cls : "modal-content",
2272 cls : 'modal-header',
2277 cls : 'modal-footer',
2281 cls: 'btn-' + this.buttonPosition
2298 modal.cls += ' fade';
2304 getChildContainer : function() {
2309 getButtonContainer : function() {
2310 return this.el.select('.modal-footer div',true).first();
2313 initEvents : function()
2315 if (this.allow_close) {
2316 this.closeEl.on('click', this.hide, this);
2322 if (!this.rendered) {
2326 this.el.setStyle('display', 'block');
2330 (function(){ _this.el.addClass('in'); }).defer(50);
2332 this.el.addClass('in');
2335 // not sure how we can show data in here..
2337 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2340 Roo.get(document.body).addClass("x-body-masked");
2341 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2343 this.el.setStyle('zIndex', '10001');
2345 this.fireEvent('show', this);
2352 Roo.get(document.body).removeClass("x-body-masked");
2353 this.el.removeClass('in');
2357 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2359 this.el.setStyle('display', 'none');
2362 this.fireEvent('hide', this);
2365 addButton : function(str, cb)
2369 var b = Roo.apply({}, { html : str } );
2370 b.xns = b.xns || Roo.bootstrap;
2371 b.xtype = b.xtype || 'Button';
2372 if (typeof(b.listeners) == 'undefined') {
2373 b.listeners = { click : cb.createDelegate(this) };
2376 var btn = Roo.factory(b);
2378 btn.onRender(this.el.select('.modal-footer div').first());
2384 setDefaultButton : function(btn)
2386 //this.el.select('.modal-footer').()
2388 resizeTo: function(w,h)
2392 setContentSize : function(w, h)
2396 onButtonClick: function(btn,e)
2399 this.fireEvent('btnclick', btn.name, e);
2402 * Set the title of the Dialog
2403 * @param {String} str new Title
2405 setTitle: function(str) {
2406 this.titleEl.dom.innerHTML = str;
2409 * Set the body of the Dialog
2410 * @param {String} str new Title
2412 setBody: function(str) {
2413 this.bodyEl.dom.innerHTML = str;
2416 * Set the body of the Dialog using the template
2417 * @param {Obj} data - apply this data to the template and replace the body contents.
2419 applyBody: function(obj)
2422 Roo.log("Error - using apply Body without a template");
2425 this.tmpl.overwrite(this.bodyEl, obj);
2431 Roo.apply(Roo.bootstrap.Modal, {
2433 * Button config that displays a single OK button
2442 * Button config that displays Yes and No buttons
2458 * Button config that displays OK and Cancel buttons
2473 * Button config that displays Yes, No and Cancel buttons
2496 * messagebox - can be used as a replace
2500 * @class Roo.MessageBox
2501 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2505 Roo.Msg.alert('Status', 'Changes saved successfully.');
2507 // Prompt for user data:
2508 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2510 // process text value...
2514 // Show a dialog using config options:
2516 title:'Save Changes?',
2517 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2518 buttons: Roo.Msg.YESNOCANCEL,
2525 Roo.bootstrap.MessageBox = function(){
2526 var dlg, opt, mask, waitTimer;
2527 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2528 var buttons, activeTextEl, bwidth;
2532 var handleButton = function(button){
2534 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2538 var handleHide = function(){
2540 dlg.el.removeClass(opt.cls);
2543 // Roo.TaskMgr.stop(waitTimer);
2544 // waitTimer = null;
2549 var updateButtons = function(b){
2552 buttons["ok"].hide();
2553 buttons["cancel"].hide();
2554 buttons["yes"].hide();
2555 buttons["no"].hide();
2556 //dlg.footer.dom.style.display = 'none';
2559 dlg.footerEl.dom.style.display = '';
2560 for(var k in buttons){
2561 if(typeof buttons[k] != "function"){
2564 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2565 width += buttons[k].el.getWidth()+15;
2575 var handleEsc = function(d, k, e){
2576 if(opt && opt.closable !== false){
2586 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2587 * @return {Roo.BasicDialog} The BasicDialog element
2589 getDialog : function(){
2591 dlg = new Roo.bootstrap.Modal( {
2594 //constraintoviewport:false,
2596 //collapsible : false,
2601 //buttonAlign:"center",
2602 closeClick : function(){
2603 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2606 handleButton("cancel");
2611 dlg.on("hide", handleHide);
2613 //dlg.addKeyListener(27, handleEsc);
2615 this.buttons = buttons;
2616 var bt = this.buttonText;
2617 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2618 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2619 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2620 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2622 bodyEl = dlg.bodyEl.createChild({
2624 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2625 '<textarea class="roo-mb-textarea"></textarea>' +
2626 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2628 msgEl = bodyEl.dom.firstChild;
2629 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2630 textboxEl.enableDisplayMode();
2631 textboxEl.addKeyListener([10,13], function(){
2632 if(dlg.isVisible() && opt && opt.buttons){
2635 }else if(opt.buttons.yes){
2636 handleButton("yes");
2640 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2641 textareaEl.enableDisplayMode();
2642 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2643 progressEl.enableDisplayMode();
2644 var pf = progressEl.dom.firstChild;
2646 pp = Roo.get(pf.firstChild);
2647 pp.setHeight(pf.offsetHeight);
2655 * Updates the message box body text
2656 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2657 * the XHTML-compliant non-breaking space character '&#160;')
2658 * @return {Roo.MessageBox} This message box
2660 updateText : function(text){
2661 if(!dlg.isVisible() && !opt.width){
2662 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2664 msgEl.innerHTML = text || ' ';
2666 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2667 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2669 Math.min(opt.width || cw , this.maxWidth),
2670 Math.max(opt.minWidth || this.minWidth, bwidth)
2673 activeTextEl.setWidth(w);
2675 if(dlg.isVisible()){
2676 dlg.fixedcenter = false;
2678 // to big, make it scroll. = But as usual stupid IE does not support
2681 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2682 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2683 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2685 bodyEl.dom.style.height = '';
2686 bodyEl.dom.style.overflowY = '';
2689 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2691 bodyEl.dom.style.overflowX = '';
2694 dlg.setContentSize(w, bodyEl.getHeight());
2695 if(dlg.isVisible()){
2696 dlg.fixedcenter = true;
2702 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2703 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2704 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2705 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2706 * @return {Roo.MessageBox} This message box
2708 updateProgress : function(value, text){
2710 this.updateText(text);
2712 if (pp) { // weird bug on my firefox - for some reason this is not defined
2713 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2719 * Returns true if the message box is currently displayed
2720 * @return {Boolean} True if the message box is visible, else false
2722 isVisible : function(){
2723 return dlg && dlg.isVisible();
2727 * Hides the message box if it is displayed
2730 if(this.isVisible()){
2736 * Displays a new message box, or reinitializes an existing message box, based on the config options
2737 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2738 * The following config object properties are supported:
2740 Property Type Description
2741 ---------- --------------- ------------------------------------------------------------------------------------
2742 animEl String/Element An id or Element from which the message box should animate as it opens and
2743 closes (defaults to undefined)
2744 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2745 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2746 closable Boolean False to hide the top-right close button (defaults to true). Note that
2747 progress and wait dialogs will ignore this property and always hide the
2748 close button as they can only be closed programmatically.
2749 cls String A custom CSS class to apply to the message box element
2750 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2751 displayed (defaults to 75)
2752 fn Function A callback function to execute after closing the dialog. The arguments to the
2753 function will be btn (the name of the button that was clicked, if applicable,
2754 e.g. "ok"), and text (the value of the active text field, if applicable).
2755 Progress and wait dialogs will ignore this option since they do not respond to
2756 user actions and can only be closed programmatically, so any required function
2757 should be called by the same code after it closes the dialog.
2758 icon String A CSS class that provides a background image to be used as an icon for
2759 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2760 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2761 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2762 modal Boolean False to allow user interaction with the page while the message box is
2763 displayed (defaults to true)
2764 msg String A string that will replace the existing message box body text (defaults
2765 to the XHTML-compliant non-breaking space character ' ')
2766 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2767 progress Boolean True to display a progress bar (defaults to false)
2768 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2769 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2770 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2771 title String The title text
2772 value String The string value to set into the active textbox element if displayed
2773 wait Boolean True to display a progress bar (defaults to false)
2774 width Number The width of the dialog in pixels
2781 msg: 'Please enter your address:',
2783 buttons: Roo.MessageBox.OKCANCEL,
2786 animEl: 'addAddressBtn'
2789 * @param {Object} config Configuration options
2790 * @return {Roo.MessageBox} This message box
2792 show : function(options)
2795 // this causes nightmares if you show one dialog after another
2796 // especially on callbacks..
2798 if(this.isVisible()){
2801 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2802 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2803 Roo.log("New Dialog Message:" + options.msg )
2804 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2805 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2808 var d = this.getDialog();
2810 d.setTitle(opt.title || " ");
2811 d.closeEl.setDisplayed(opt.closable !== false);
2812 activeTextEl = textboxEl;
2813 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2818 textareaEl.setHeight(typeof opt.multiline == "number" ?
2819 opt.multiline : this.defaultTextHeight);
2820 activeTextEl = textareaEl;
2829 progressEl.setDisplayed(opt.progress === true);
2830 this.updateProgress(0);
2831 activeTextEl.dom.value = opt.value || "";
2833 dlg.setDefaultButton(activeTextEl);
2835 var bs = opt.buttons;
2839 }else if(bs && bs.yes){
2840 db = buttons["yes"];
2842 dlg.setDefaultButton(db);
2844 bwidth = updateButtons(opt.buttons);
2845 this.updateText(opt.msg);
2847 d.el.addClass(opt.cls);
2849 d.proxyDrag = opt.proxyDrag === true;
2850 d.modal = opt.modal !== false;
2851 d.mask = opt.modal !== false ? mask : false;
2853 // force it to the end of the z-index stack so it gets a cursor in FF
2854 document.body.appendChild(dlg.el.dom);
2855 d.animateTarget = null;
2856 d.show(options.animEl);
2862 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2863 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2864 * and closing the message box when the process is complete.
2865 * @param {String} title The title bar text
2866 * @param {String} msg The message box body text
2867 * @return {Roo.MessageBox} This message box
2869 progress : function(title, msg){
2876 minWidth: this.minProgressWidth,
2883 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2884 * If a callback function is passed it will be called after the user clicks the button, and the
2885 * id of the button that was clicked will be passed as the only parameter to the callback
2886 * (could also be the top-right close button).
2887 * @param {String} title The title bar text
2888 * @param {String} msg The message box body text
2889 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2890 * @param {Object} scope (optional) The scope of the callback function
2891 * @return {Roo.MessageBox} This message box
2893 alert : function(title, msg, fn, scope){
2906 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2907 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2908 * You are responsible for closing the message box when the process is complete.
2909 * @param {String} msg The message box body text
2910 * @param {String} title (optional) The title bar text
2911 * @return {Roo.MessageBox} This message box
2913 wait : function(msg, title){
2924 waitTimer = Roo.TaskMgr.start({
2926 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2934 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2935 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2936 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2937 * @param {String} title The title bar text
2938 * @param {String} msg The message box body text
2939 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2940 * @param {Object} scope (optional) The scope of the callback function
2941 * @return {Roo.MessageBox} This message box
2943 confirm : function(title, msg, fn, scope){
2947 buttons: this.YESNO,
2956 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2957 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2958 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2959 * (could also be the top-right close button) and the text that was entered will be passed as the two
2960 * parameters to the callback.
2961 * @param {String} title The title bar text
2962 * @param {String} msg The message box body text
2963 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2964 * @param {Object} scope (optional) The scope of the callback function
2965 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2966 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2967 * @return {Roo.MessageBox} This message box
2969 prompt : function(title, msg, fn, scope, multiline){
2973 buttons: this.OKCANCEL,
2978 multiline: multiline,
2985 * Button config that displays a single OK button
2990 * Button config that displays Yes and No buttons
2993 YESNO : {yes:true, no:true},
2995 * Button config that displays OK and Cancel buttons
2998 OKCANCEL : {ok:true, cancel:true},
3000 * Button config that displays Yes, No and Cancel buttons
3003 YESNOCANCEL : {yes:true, no:true, cancel:true},
3006 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3009 defaultTextHeight : 75,
3011 * The maximum width in pixels of the message box (defaults to 600)
3016 * The minimum width in pixels of the message box (defaults to 100)
3021 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3022 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3025 minProgressWidth : 250,
3027 * An object containing the default button text strings that can be overriden for localized language support.
3028 * Supported properties are: ok, cancel, yes and no.
3029 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3042 * Shorthand for {@link Roo.MessageBox}
3044 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3045 Roo.Msg = Roo.Msg || Roo.MessageBox;
3054 * @class Roo.bootstrap.Navbar
3055 * @extends Roo.bootstrap.Component
3056 * Bootstrap Navbar class
3059 * Create a new Navbar
3060 * @param {Object} config The config object
3064 Roo.bootstrap.Navbar = function(config){
3065 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3069 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3078 getAutoCreate : function(){
3081 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3085 initEvents :function ()
3087 //Roo.log(this.el.select('.navbar-toggle',true));
3088 this.el.select('.navbar-toggle',true).on('click', function() {
3089 // Roo.log('click');
3090 this.el.select('.navbar-collapse',true).toggleClass('in');
3098 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3100 var size = this.el.getSize();
3101 this.maskEl.setSize(size.width, size.height);
3102 this.maskEl.enableDisplayMode("block");
3111 getChildContainer : function()
3113 if (this.el.select('.collapse').getCount()) {
3114 return this.el.select('.collapse',true).first();
3147 * @class Roo.bootstrap.NavSimplebar
3148 * @extends Roo.bootstrap.Navbar
3149 * Bootstrap Sidebar class
3151 * @cfg {Boolean} inverse is inverted color
3153 * @cfg {String} type (nav | pills | tabs)
3154 * @cfg {Boolean} arrangement stacked | justified
3155 * @cfg {String} align (left | right) alignment
3157 * @cfg {Boolean} main (true|false) main nav bar? default false
3158 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3160 * @cfg {String} tag (header|footer|nav|div) default is nav
3166 * Create a new Sidebar
3167 * @param {Object} config The config object
3171 Roo.bootstrap.NavSimplebar = function(config){
3172 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3175 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3191 getAutoCreate : function(){
3195 tag : this.tag || 'div',
3208 this.type = this.type || 'nav';
3209 if (['tabs','pills'].indexOf(this.type)!==-1) {
3210 cfg.cn[0].cls += ' nav-' + this.type
3214 if (this.type!=='nav') {
3215 Roo.log('nav type must be nav/tabs/pills')
3217 cfg.cn[0].cls += ' navbar-nav'
3223 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3224 cfg.cn[0].cls += ' nav-' + this.arrangement;
3228 if (this.align === 'right') {
3229 cfg.cn[0].cls += ' navbar-right';
3233 cfg.cls += ' navbar-inverse';
3260 * @class Roo.bootstrap.NavHeaderbar
3261 * @extends Roo.bootstrap.NavSimplebar
3262 * Bootstrap Sidebar class
3264 * @cfg {String} brand what is brand
3265 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3266 * @cfg {String} brand_href href of the brand
3267 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3268 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3269 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3270 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3273 * Create a new Sidebar
3274 * @param {Object} config The config object
3278 Roo.bootstrap.NavHeaderbar = function(config){
3279 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3283 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3290 desktopCenter : false,
3293 getAutoCreate : function(){
3296 tag: this.nav || 'nav',
3303 if (this.desktopCenter) {
3304 cn.push({cls : 'container', cn : []});
3311 cls: 'navbar-header',
3316 cls: 'navbar-toggle',
3317 'data-toggle': 'collapse',
3322 html: 'Toggle navigation'
3344 cls: 'collapse navbar-collapse',
3348 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3350 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3351 cfg.cls += ' navbar-' + this.position;
3353 // tag can override this..
3355 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3358 if (this.brand !== '') {
3361 href: this.brand_href ? this.brand_href : '#',
3362 cls: 'navbar-brand',
3370 cfg.cls += ' main-nav';
3378 getHeaderChildContainer : function()
3380 if (this.el.select('.navbar-header').getCount()) {
3381 return this.el.select('.navbar-header',true).first();
3384 return this.getChildContainer();
3388 initEvents : function()
3390 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3392 if (this.autohide) {
3397 Roo.get(document).on('scroll',function(e) {
3398 var ns = Roo.get(document).getScroll().top;
3399 var os = prevScroll;
3403 ft.removeClass('slideDown');
3404 ft.addClass('slideUp');
3407 ft.removeClass('slideUp');
3408 ft.addClass('slideDown');
3432 * @class Roo.bootstrap.NavSidebar
3433 * @extends Roo.bootstrap.Navbar
3434 * Bootstrap Sidebar class
3437 * Create a new Sidebar
3438 * @param {Object} config The config object
3442 Roo.bootstrap.NavSidebar = function(config){
3443 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3446 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3448 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3450 getAutoCreate : function(){
3455 cls: 'sidebar sidebar-nav'
3477 * @class Roo.bootstrap.NavGroup
3478 * @extends Roo.bootstrap.Component
3479 * Bootstrap NavGroup class
3480 * @cfg {String} align left | right
3481 * @cfg {Boolean} inverse false | true
3482 * @cfg {String} type (nav|pills|tab) default nav
3483 * @cfg {String} navId - reference Id for navbar.
3487 * Create a new nav group
3488 * @param {Object} config The config object
3491 Roo.bootstrap.NavGroup = function(config){
3492 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3495 Roo.bootstrap.NavGroup.register(this);
3499 * Fires when the active item changes
3500 * @param {Roo.bootstrap.NavGroup} this
3501 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3502 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3509 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3520 getAutoCreate : function()
3522 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3529 if (['tabs','pills'].indexOf(this.type)!==-1) {
3530 cfg.cls += ' nav-' + this.type
3532 if (this.type!=='nav') {
3533 Roo.log('nav type must be nav/tabs/pills')
3535 cfg.cls += ' navbar-nav'
3538 if (this.parent().sidebar) {
3541 cls: 'dashboard-menu sidebar-menu'
3547 if (this.form === true) {
3553 if (this.align === 'right') {
3554 cfg.cls += ' navbar-right';
3556 cfg.cls += ' navbar-left';
3560 if (this.align === 'right') {
3561 cfg.cls += ' navbar-right';
3565 cfg.cls += ' navbar-inverse';
3573 * sets the active Navigation item
3574 * @param {Roo.bootstrap.NavItem} the new current navitem
3576 setActiveItem : function(item)
3579 Roo.each(this.navItems, function(v){
3584 v.setActive(false, true);
3591 item.setActive(true, true);
3592 this.fireEvent('changed', this, item, prev);
3597 * gets the active Navigation item
3598 * @return {Roo.bootstrap.NavItem} the current navitem
3600 getActive : function()
3604 Roo.each(this.navItems, function(v){
3615 indexOfNav : function()
3619 Roo.each(this.navItems, function(v,i){
3630 * adds a Navigation item
3631 * @param {Roo.bootstrap.NavItem} the navitem to add
3633 addItem : function(cfg)
3635 var cn = new Roo.bootstrap.NavItem(cfg);
3637 cn.parentId = this.id;
3638 cn.onRender(this.el, null);
3642 * register a Navigation item
3643 * @param {Roo.bootstrap.NavItem} the navitem to add
3645 register : function(item)
3647 this.navItems.push( item);
3648 item.navId = this.navId;
3653 * clear all the Navigation item
3656 clearAll : function()
3659 this.el.dom.innerHTML = '';
3662 getNavItem: function(tabId)
3665 Roo.each(this.navItems, function(e) {
3666 if (e.tabId == tabId) {
3676 setActiveNext : function()
3678 var i = this.indexOfNav(this.getActive());
3679 if (i > this.navItems.length) {
3682 this.setActiveItem(this.navItems[i+1]);
3684 setActivePrev : function()
3686 var i = this.indexOfNav(this.getActive());
3690 this.setActiveItem(this.navItems[i-1]);
3692 clearWasActive : function(except) {
3693 Roo.each(this.navItems, function(e) {
3694 if (e.tabId != except.tabId && e.was_active) {
3695 e.was_active = false;
3702 getWasActive : function ()
3705 Roo.each(this.navItems, function(e) {
3720 Roo.apply(Roo.bootstrap.NavGroup, {
3724 * register a Navigation Group
3725 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3727 register : function(navgrp)
3729 this.groups[navgrp.navId] = navgrp;
3733 * fetch a Navigation Group based on the navigation ID
3734 * @param {string} the navgroup to add
3735 * @returns {Roo.bootstrap.NavGroup} the navgroup
3737 get: function(navId) {
3738 if (typeof(this.groups[navId]) == 'undefined') {
3740 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3742 return this.groups[navId] ;
3757 * @class Roo.bootstrap.NavItem
3758 * @extends Roo.bootstrap.Component
3759 * Bootstrap Navbar.NavItem class
3760 * @cfg {String} href link to
3761 * @cfg {String} html content of button
3762 * @cfg {String} badge text inside badge
3763 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3764 * @cfg {String} glyphicon name of glyphicon
3765 * @cfg {String} icon name of font awesome icon
3766 * @cfg {Boolean} active Is item active
3767 * @cfg {Boolean} disabled Is item disabled
3769 * @cfg {Boolean} preventDefault (true | false) default false
3770 * @cfg {String} tabId the tab that this item activates.
3771 * @cfg {String} tagtype (a|span) render as a href or span?
3772 * @cfg {Boolean} animateRef (true|false) link to element default false
3775 * Create a new Navbar Item
3776 * @param {Object} config The config object
3778 Roo.bootstrap.NavItem = function(config){
3779 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3784 * The raw click event for the entire grid.
3785 * @param {Roo.EventObject} e
3790 * Fires when the active item active state changes
3791 * @param {Roo.bootstrap.NavItem} this
3792 * @param {boolean} state the new state
3798 * Fires when scroll to element
3799 * @param {Roo.bootstrap.NavItem} this
3800 * @param {Object} options
3801 * @param {Roo.EventObject} e
3809 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3817 preventDefault : false,
3824 getAutoCreate : function(){
3832 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3834 if (this.disabled) {
3835 cfg.cls += ' disabled';
3838 if (this.href || this.html || this.glyphicon || this.icon) {
3842 href : this.href || "#",
3843 html: this.html || ''
3848 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3851 if(this.glyphicon) {
3852 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3857 cfg.cn[0].html += " <span class='caret'></span>";
3861 if (this.badge !== '') {
3863 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3871 initEvents: function()
3873 if (typeof (this.menu) != 'undefined') {
3874 this.menu.parentType = this.xtype;
3875 this.menu.triggerEl = this.el;
3876 this.menu = this.addxtype(Roo.apply({}, this.menu));
3879 this.el.select('a',true).on('click', this.onClick, this);
3881 if(this.tagtype == 'span'){
3882 this.el.select('span',true).on('click', this.onClick, this);
3885 // at this point parent should be available..
3886 this.parent().register(this);
3889 onClick : function(e)
3892 this.preventDefault ||
3899 if (this.disabled) {
3903 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3904 if (tg && tg.transition) {
3905 Roo.log("waiting for the transitionend");
3911 Roo.log("fire event clicked");
3912 if(this.fireEvent('click', this, e) === false){
3916 if(this.tagtype == 'span'){
3919 var p = this.parent();
3922 var ael = this.el.select('a',true).first();
3925 if(ael && this.animateRef && this.href.indexOf('#') > -1){
3926 Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
3927 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
3928 return; // ignore... - it's a 'hash' to another page.
3932 this.scrollToElement(e);
3940 if (['tabs','pills'].indexOf(this.type)!==-1) {
3941 if (typeof(p.setActiveItem) !== 'undefined') {
3942 p.setActiveItem(this);
3947 isActive: function () {
3950 setActive : function(state, fire, is_was_active)
3952 if (this.active && !state & this.navId) {
3953 this.was_active = true;
3954 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3956 nv.clearWasActive(this);
3960 this.active = state;
3963 this.el.removeClass('active');
3964 } else if (!this.el.hasClass('active')) {
3965 this.el.addClass('active');
3968 this.fireEvent('changed', this, state);
3971 // show a panel if it's registered and related..
3973 if (!this.navId || !this.tabId || !state || is_was_active) {
3977 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3981 var pan = tg.getPanelByName(this.tabId);
3985 // if we can not flip to new panel - go back to old nav highlight..
3986 if (false == tg.showPanel(pan)) {
3987 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3989 var onav = nv.getWasActive();
3991 onav.setActive(true, false, true);
4000 // this should not be here...
4001 setDisabled : function(state)
4003 this.disabled = state;
4005 this.el.removeClass('disabled');
4006 } else if (!this.el.hasClass('disabled')) {
4007 this.el.addClass('disabled');
4013 * Fetch the element to display the tooltip on.
4014 * @return {Roo.Element} defaults to this.el
4016 tooltipEl : function()
4018 return this.el.select('' + this.tagtype + '', true).first();
4021 scrollToElement : function(e)
4023 var c = document.body;
4025 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4031 var o = target.calcOffsetsTo(c);
4038 this.fireEvent('scrollto', this, options, e);
4040 Roo.get(c).scrollTo('top', options.value, true);
4053 * <span> icon </span>
4054 * <span> text </span>
4055 * <span>badge </span>
4059 * @class Roo.bootstrap.NavSidebarItem
4060 * @extends Roo.bootstrap.NavItem
4061 * Bootstrap Navbar.NavSidebarItem class
4063 * Create a new Navbar Button
4064 * @param {Object} config The config object
4066 Roo.bootstrap.NavSidebarItem = function(config){
4067 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4072 * The raw click event for the entire grid.
4073 * @param {Roo.EventObject} e
4078 * Fires when the active item active state changes
4079 * @param {Roo.bootstrap.NavSidebarItem} this
4080 * @param {boolean} state the new state
4088 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4091 getAutoCreate : function(){
4096 href : this.href || '#',
4108 html : this.html || ''
4113 cfg.cls += ' active';
4117 if (this.glyphicon || this.icon) {
4118 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4119 a.cn.push({ tag : 'i', cls : c }) ;
4124 if (this.badge !== '') {
4125 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4129 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4130 a.cls += 'dropdown-toggle treeview' ;
4154 * @class Roo.bootstrap.Row
4155 * @extends Roo.bootstrap.Component
4156 * Bootstrap Row class (contains columns...)
4160 * @param {Object} config The config object
4163 Roo.bootstrap.Row = function(config){
4164 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4167 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4169 getAutoCreate : function(){
4188 * @class Roo.bootstrap.Element
4189 * @extends Roo.bootstrap.Component
4190 * Bootstrap Element class
4191 * @cfg {String} html contents of the element
4192 * @cfg {String} tag tag of the element
4193 * @cfg {String} cls class of the element
4194 * @cfg {Boolean} preventDefault (true|false) default false
4195 * @cfg {Boolean} clickable (true|false) default false
4198 * Create a new Element
4199 * @param {Object} config The config object
4202 Roo.bootstrap.Element = function(config){
4203 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4209 * When a element is chick
4210 * @param {Roo.bootstrap.Element} this
4211 * @param {Roo.EventObject} e
4217 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4222 preventDefault: false,
4225 getAutoCreate : function(){
4236 initEvents: function()
4238 Roo.bootstrap.Element.superclass.initEvents.call(this);
4241 this.el.on('click', this.onClick, this);
4246 onClick : function(e)
4248 if(this.preventDefault){
4252 this.fireEvent('click', this, e);
4255 getValue : function()
4257 return this.el.dom.innerHTML;
4260 setValue : function(value)
4262 this.el.dom.innerHTML = value;
4277 * @class Roo.bootstrap.Pagination
4278 * @extends Roo.bootstrap.Component
4279 * Bootstrap Pagination class
4280 * @cfg {String} size xs | sm | md | lg
4281 * @cfg {Boolean} inverse false | true
4284 * Create a new Pagination
4285 * @param {Object} config The config object
4288 Roo.bootstrap.Pagination = function(config){
4289 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4292 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4298 getAutoCreate : function(){
4304 cfg.cls += ' inverse';
4310 cfg.cls += " " + this.cls;
4328 * @class Roo.bootstrap.PaginationItem
4329 * @extends Roo.bootstrap.Component
4330 * Bootstrap PaginationItem class
4331 * @cfg {String} html text
4332 * @cfg {String} href the link
4333 * @cfg {Boolean} preventDefault (true | false) default true
4334 * @cfg {Boolean} active (true | false) default false
4335 * @cfg {Boolean} disabled default false
4339 * Create a new PaginationItem
4340 * @param {Object} config The config object
4344 Roo.bootstrap.PaginationItem = function(config){
4345 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4350 * The raw click event for the entire grid.
4351 * @param {Roo.EventObject} e
4357 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4361 preventDefault: true,
4366 getAutoCreate : function(){
4372 href : this.href ? this.href : '#',
4373 html : this.html ? this.html : ''
4383 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4387 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4393 initEvents: function() {
4395 this.el.on('click', this.onClick, this);
4398 onClick : function(e)
4400 Roo.log('PaginationItem on click ');
4401 if(this.preventDefault){
4409 this.fireEvent('click', this, e);
4425 * @class Roo.bootstrap.Slider
4426 * @extends Roo.bootstrap.Component
4427 * Bootstrap Slider class
4430 * Create a new Slider
4431 * @param {Object} config The config object
4434 Roo.bootstrap.Slider = function(config){
4435 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4438 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4440 getAutoCreate : function(){
4444 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4448 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4460 * Ext JS Library 1.1.1
4461 * Copyright(c) 2006-2007, Ext JS, LLC.
4463 * Originally Released Under LGPL - original licence link has changed is not relivant.
4466 * <script type="text/javascript">
4471 * @class Roo.grid.ColumnModel
4472 * @extends Roo.util.Observable
4473 * This is the default implementation of a ColumnModel used by the Grid. It defines
4474 * the columns in the grid.
4477 var colModel = new Roo.grid.ColumnModel([
4478 {header: "Ticker", width: 60, sortable: true, locked: true},
4479 {header: "Company Name", width: 150, sortable: true},
4480 {header: "Market Cap.", width: 100, sortable: true},
4481 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4482 {header: "Employees", width: 100, sortable: true, resizable: false}
4487 * The config options listed for this class are options which may appear in each
4488 * individual column definition.
4489 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4491 * @param {Object} config An Array of column config objects. See this class's
4492 * config objects for details.
4494 Roo.grid.ColumnModel = function(config){
4496 * The config passed into the constructor
4498 this.config = config;
4501 // if no id, create one
4502 // if the column does not have a dataIndex mapping,
4503 // map it to the order it is in the config
4504 for(var i = 0, len = config.length; i < len; i++){
4506 if(typeof c.dataIndex == "undefined"){
4509 if(typeof c.renderer == "string"){
4510 c.renderer = Roo.util.Format[c.renderer];
4512 if(typeof c.id == "undefined"){
4515 if(c.editor && c.editor.xtype){
4516 c.editor = Roo.factory(c.editor, Roo.grid);
4518 if(c.editor && c.editor.isFormField){
4519 c.editor = new Roo.grid.GridEditor(c.editor);
4521 this.lookup[c.id] = c;
4525 * The width of columns which have no width specified (defaults to 100)
4528 this.defaultWidth = 100;
4531 * Default sortable of columns which have no sortable specified (defaults to false)
4534 this.defaultSortable = false;
4538 * @event widthchange
4539 * Fires when the width of a column changes.
4540 * @param {ColumnModel} this
4541 * @param {Number} columnIndex The column index
4542 * @param {Number} newWidth The new width
4544 "widthchange": true,
4546 * @event headerchange
4547 * Fires when the text of a header changes.
4548 * @param {ColumnModel} this
4549 * @param {Number} columnIndex The column index
4550 * @param {Number} newText The new header text
4552 "headerchange": true,
4554 * @event hiddenchange
4555 * Fires when a column is hidden or "unhidden".
4556 * @param {ColumnModel} this
4557 * @param {Number} columnIndex The column index
4558 * @param {Boolean} hidden true if hidden, false otherwise
4560 "hiddenchange": true,
4562 * @event columnmoved
4563 * Fires when a column is moved.
4564 * @param {ColumnModel} this
4565 * @param {Number} oldIndex
4566 * @param {Number} newIndex
4568 "columnmoved" : true,
4570 * @event columlockchange
4571 * Fires when a column's locked state is changed
4572 * @param {ColumnModel} this
4573 * @param {Number} colIndex
4574 * @param {Boolean} locked true if locked
4576 "columnlockchange" : true
4578 Roo.grid.ColumnModel.superclass.constructor.call(this);
4580 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4582 * @cfg {String} header The header text to display in the Grid view.
4585 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4586 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4587 * specified, the column's index is used as an index into the Record's data Array.
4590 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4591 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4594 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4595 * Defaults to the value of the {@link #defaultSortable} property.
4596 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4599 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4602 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4605 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4608 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4611 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4612 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4613 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4614 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4617 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4620 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4623 * @cfg {String} cursor (Optional)
4626 * @cfg {String} tooltip (Optional)
4629 * Returns the id of the column at the specified index.
4630 * @param {Number} index The column index
4631 * @return {String} the id
4633 getColumnId : function(index){
4634 return this.config[index].id;
4638 * Returns the column for a specified id.
4639 * @param {String} id The column id
4640 * @return {Object} the column
4642 getColumnById : function(id){
4643 return this.lookup[id];
4648 * Returns the column for a specified dataIndex.
4649 * @param {String} dataIndex The column dataIndex
4650 * @return {Object|Boolean} the column or false if not found
4652 getColumnByDataIndex: function(dataIndex){
4653 var index = this.findColumnIndex(dataIndex);
4654 return index > -1 ? this.config[index] : false;
4658 * Returns the index for a specified column id.
4659 * @param {String} id The column id
4660 * @return {Number} the index, or -1 if not found
4662 getIndexById : function(id){
4663 for(var i = 0, len = this.config.length; i < len; i++){
4664 if(this.config[i].id == id){
4672 * Returns the index for a specified column dataIndex.
4673 * @param {String} dataIndex The column dataIndex
4674 * @return {Number} the index, or -1 if not found
4677 findColumnIndex : function(dataIndex){
4678 for(var i = 0, len = this.config.length; i < len; i++){
4679 if(this.config[i].dataIndex == dataIndex){
4687 moveColumn : function(oldIndex, newIndex){
4688 var c = this.config[oldIndex];
4689 this.config.splice(oldIndex, 1);
4690 this.config.splice(newIndex, 0, c);
4691 this.dataMap = null;
4692 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4695 isLocked : function(colIndex){
4696 return this.config[colIndex].locked === true;
4699 setLocked : function(colIndex, value, suppressEvent){
4700 if(this.isLocked(colIndex) == value){
4703 this.config[colIndex].locked = value;
4705 this.fireEvent("columnlockchange", this, colIndex, value);
4709 getTotalLockedWidth : function(){
4711 for(var i = 0; i < this.config.length; i++){
4712 if(this.isLocked(i) && !this.isHidden(i)){
4713 this.totalWidth += this.getColumnWidth(i);
4719 getLockedCount : function(){
4720 for(var i = 0, len = this.config.length; i < len; i++){
4721 if(!this.isLocked(i)){
4728 * Returns the number of columns.
4731 getColumnCount : function(visibleOnly){
4732 if(visibleOnly === true){
4734 for(var i = 0, len = this.config.length; i < len; i++){
4735 if(!this.isHidden(i)){
4741 return this.config.length;
4745 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4746 * @param {Function} fn
4747 * @param {Object} scope (optional)
4748 * @return {Array} result
4750 getColumnsBy : function(fn, scope){
4752 for(var i = 0, len = this.config.length; i < len; i++){
4753 var c = this.config[i];
4754 if(fn.call(scope||this, c, i) === true){
4762 * Returns true if the specified column is sortable.
4763 * @param {Number} col The column index
4766 isSortable : function(col){
4767 if(typeof this.config[col].sortable == "undefined"){
4768 return this.defaultSortable;
4770 return this.config[col].sortable;
4774 * Returns the rendering (formatting) function defined for the column.
4775 * @param {Number} col The column index.
4776 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4778 getRenderer : function(col){
4779 if(!this.config[col].renderer){
4780 return Roo.grid.ColumnModel.defaultRenderer;
4782 return this.config[col].renderer;
4786 * Sets the rendering (formatting) function for a column.
4787 * @param {Number} col The column index
4788 * @param {Function} fn The function to use to process the cell's raw data
4789 * to return HTML markup for the grid view. The render function is called with
4790 * the following parameters:<ul>
4791 * <li>Data value.</li>
4792 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4793 * <li>css A CSS style string to apply to the table cell.</li>
4794 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4795 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4796 * <li>Row index</li>
4797 * <li>Column index</li>
4798 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4800 setRenderer : function(col, fn){
4801 this.config[col].renderer = fn;
4805 * Returns the width for the specified column.
4806 * @param {Number} col The column index
4809 getColumnWidth : function(col){
4810 return this.config[col].width * 1 || this.defaultWidth;
4814 * Sets the width for a column.
4815 * @param {Number} col The column index
4816 * @param {Number} width The new width
4818 setColumnWidth : function(col, width, suppressEvent){
4819 this.config[col].width = width;
4820 this.totalWidth = null;
4822 this.fireEvent("widthchange", this, col, width);
4827 * Returns the total width of all columns.
4828 * @param {Boolean} includeHidden True to include hidden column widths
4831 getTotalWidth : function(includeHidden){
4832 if(!this.totalWidth){
4833 this.totalWidth = 0;
4834 for(var i = 0, len = this.config.length; i < len; i++){
4835 if(includeHidden || !this.isHidden(i)){
4836 this.totalWidth += this.getColumnWidth(i);
4840 return this.totalWidth;
4844 * Returns the header for the specified column.
4845 * @param {Number} col The column index
4848 getColumnHeader : function(col){
4849 return this.config[col].header;
4853 * Sets the header for a column.
4854 * @param {Number} col The column index
4855 * @param {String} header The new header
4857 setColumnHeader : function(col, header){
4858 this.config[col].header = header;
4859 this.fireEvent("headerchange", this, col, header);
4863 * Returns the tooltip for the specified column.
4864 * @param {Number} col The column index
4867 getColumnTooltip : function(col){
4868 return this.config[col].tooltip;
4871 * Sets the tooltip for a column.
4872 * @param {Number} col The column index
4873 * @param {String} tooltip The new tooltip
4875 setColumnTooltip : function(col, tooltip){
4876 this.config[col].tooltip = tooltip;
4880 * Returns the dataIndex for the specified column.
4881 * @param {Number} col The column index
4884 getDataIndex : function(col){
4885 return this.config[col].dataIndex;
4889 * Sets the dataIndex for a column.
4890 * @param {Number} col The column index
4891 * @param {Number} dataIndex The new dataIndex
4893 setDataIndex : function(col, dataIndex){
4894 this.config[col].dataIndex = dataIndex;
4900 * Returns true if the cell is editable.
4901 * @param {Number} colIndex The column index
4902 * @param {Number} rowIndex The row index
4905 isCellEditable : function(colIndex, rowIndex){
4906 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4910 * Returns the editor defined for the cell/column.
4911 * return false or null to disable editing.
4912 * @param {Number} colIndex The column index
4913 * @param {Number} rowIndex The row index
4916 getCellEditor : function(colIndex, rowIndex){
4917 return this.config[colIndex].editor;
4921 * Sets if a column is editable.
4922 * @param {Number} col The column index
4923 * @param {Boolean} editable True if the column is editable
4925 setEditable : function(col, editable){
4926 this.config[col].editable = editable;
4931 * Returns true if the column is hidden.
4932 * @param {Number} colIndex The column index
4935 isHidden : function(colIndex){
4936 return this.config[colIndex].hidden;
4941 * Returns true if the column width cannot be changed
4943 isFixed : function(colIndex){
4944 return this.config[colIndex].fixed;
4948 * Returns true if the column can be resized
4951 isResizable : function(colIndex){
4952 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4955 * Sets if a column is hidden.
4956 * @param {Number} colIndex The column index
4957 * @param {Boolean} hidden True if the column is hidden
4959 setHidden : function(colIndex, hidden){
4960 this.config[colIndex].hidden = hidden;
4961 this.totalWidth = null;
4962 this.fireEvent("hiddenchange", this, colIndex, hidden);
4966 * Sets the editor for a column.
4967 * @param {Number} col The column index
4968 * @param {Object} editor The editor object
4970 setEditor : function(col, editor){
4971 this.config[col].editor = editor;
4975 Roo.grid.ColumnModel.defaultRenderer = function(value){
4976 if(typeof value == "string" && value.length < 1){
4982 // Alias for backwards compatibility
4983 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4986 * Ext JS Library 1.1.1
4987 * Copyright(c) 2006-2007, Ext JS, LLC.
4989 * Originally Released Under LGPL - original licence link has changed is not relivant.
4992 * <script type="text/javascript">
4996 * @class Roo.LoadMask
4997 * A simple utility class for generically masking elements while loading data. If the element being masked has
4998 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4999 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5000 * element's UpdateManager load indicator and will be destroyed after the initial load.
5002 * Create a new LoadMask
5003 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5004 * @param {Object} config The config object
5006 Roo.LoadMask = function(el, config){
5007 this.el = Roo.get(el);
5008 Roo.apply(this, config);
5010 this.store.on('beforeload', this.onBeforeLoad, this);
5011 this.store.on('load', this.onLoad, this);
5012 this.store.on('loadexception', this.onLoadException, this);
5013 this.removeMask = false;
5015 var um = this.el.getUpdateManager();
5016 um.showLoadIndicator = false; // disable the default indicator
5017 um.on('beforeupdate', this.onBeforeLoad, this);
5018 um.on('update', this.onLoad, this);
5019 um.on('failure', this.onLoad, this);
5020 this.removeMask = true;
5024 Roo.LoadMask.prototype = {
5026 * @cfg {Boolean} removeMask
5027 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5028 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5032 * The text to display in a centered loading message box (defaults to 'Loading...')
5036 * @cfg {String} msgCls
5037 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5039 msgCls : 'x-mask-loading',
5042 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5048 * Disables the mask to prevent it from being displayed
5050 disable : function(){
5051 this.disabled = true;
5055 * Enables the mask so that it can be displayed
5057 enable : function(){
5058 this.disabled = false;
5061 onLoadException : function()
5065 if (typeof(arguments[3]) != 'undefined') {
5066 Roo.MessageBox.alert("Error loading",arguments[3]);
5070 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5071 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5080 this.el.unmask(this.removeMask);
5085 this.el.unmask(this.removeMask);
5089 onBeforeLoad : function(){
5091 this.el.mask(this.msg, this.msgCls);
5096 destroy : function(){
5098 this.store.un('beforeload', this.onBeforeLoad, this);
5099 this.store.un('load', this.onLoad, this);
5100 this.store.un('loadexception', this.onLoadException, this);
5102 var um = this.el.getUpdateManager();
5103 um.un('beforeupdate', this.onBeforeLoad, this);
5104 um.un('update', this.onLoad, this);
5105 um.un('failure', this.onLoad, this);
5116 * @class Roo.bootstrap.Table
5117 * @extends Roo.bootstrap.Component
5118 * Bootstrap Table class
5119 * @cfg {String} cls table class
5120 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5121 * @cfg {String} bgcolor Specifies the background color for a table
5122 * @cfg {Number} border Specifies whether the table cells should have borders or not
5123 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5124 * @cfg {Number} cellspacing Specifies the space between cells
5125 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5126 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5127 * @cfg {String} sortable Specifies that the table should be sortable
5128 * @cfg {String} summary Specifies a summary of the content of a table
5129 * @cfg {Number} width Specifies the width of a table
5130 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5132 * @cfg {boolean} striped Should the rows be alternative striped
5133 * @cfg {boolean} bordered Add borders to the table
5134 * @cfg {boolean} hover Add hover highlighting
5135 * @cfg {boolean} condensed Format condensed
5136 * @cfg {boolean} responsive Format condensed
5137 * @cfg {Boolean} loadMask (true|false) default false
5138 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5139 * @cfg {Boolean} thead (true|false) generate thead, default true
5140 * @cfg {Boolean} RowSelection (true|false) default false
5141 * @cfg {Boolean} CellSelection (true|false) default false
5142 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5146 * Create a new Table
5147 * @param {Object} config The config object
5150 Roo.bootstrap.Table = function(config){
5151 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5154 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5155 this.sm = this.selModel;
5156 this.sm.xmodule = this.xmodule || false;
5158 if (this.cm && typeof(this.cm.config) == 'undefined') {
5159 this.colModel = new Roo.grid.ColumnModel(this.cm);
5160 this.cm = this.colModel;
5161 this.cm.xmodule = this.xmodule || false;
5164 this.store= Roo.factory(this.store, Roo.data);
5165 this.ds = this.store;
5166 this.ds.xmodule = this.xmodule || false;
5169 if (this.footer && this.store) {
5170 this.footer.dataSource = this.ds;
5171 this.footer = Roo.factory(this.footer);
5178 * Fires when a cell is clicked
5179 * @param {Roo.bootstrap.Table} this
5180 * @param {Roo.Element} el
5181 * @param {Number} rowIndex
5182 * @param {Number} columnIndex
5183 * @param {Roo.EventObject} e
5187 * @event celldblclick
5188 * Fires when a cell is double clicked
5189 * @param {Roo.bootstrap.Table} this
5190 * @param {Roo.Element} el
5191 * @param {Number} rowIndex
5192 * @param {Number} columnIndex
5193 * @param {Roo.EventObject} e
5195 "celldblclick" : true,
5198 * Fires when a row is clicked
5199 * @param {Roo.bootstrap.Table} this
5200 * @param {Roo.Element} el
5201 * @param {Number} rowIndex
5202 * @param {Roo.EventObject} e
5206 * @event rowdblclick
5207 * Fires when a row is double clicked
5208 * @param {Roo.bootstrap.Table} this
5209 * @param {Roo.Element} el
5210 * @param {Number} rowIndex
5211 * @param {Roo.EventObject} e
5213 "rowdblclick" : true,
5216 * Fires when a mouseover occur
5217 * @param {Roo.bootstrap.Table} this
5218 * @param {Roo.Element} el
5219 * @param {Number} rowIndex
5220 * @param {Number} columnIndex
5221 * @param {Roo.EventObject} e
5226 * Fires when a mouseout occur
5227 * @param {Roo.bootstrap.Table} this
5228 * @param {Roo.Element} el
5229 * @param {Number} rowIndex
5230 * @param {Number} columnIndex
5231 * @param {Roo.EventObject} e
5236 * Fires when a row is rendered, so you can change add a style to it.
5237 * @param {Roo.bootstrap.Table} this
5238 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5242 * @event rowsrendered
5243 * Fires when all the rows have been rendered
5244 * @param {Roo.bootstrap.Table} this
5246 'rowsrendered' : true
5251 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5275 RowSelection : false,
5276 CellSelection : false,
5279 // Roo.Element - the tbody
5282 getAutoCreate : function(){
5283 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5292 cfg.cls += ' table-striped';
5296 cfg.cls += ' table-hover';
5298 if (this.bordered) {
5299 cfg.cls += ' table-bordered';
5301 if (this.condensed) {
5302 cfg.cls += ' table-condensed';
5304 if (this.responsive) {
5305 cfg.cls += ' table-responsive';
5309 cfg.cls+= ' ' +this.cls;
5312 // this lot should be simplifed...
5315 cfg.align=this.align;
5318 cfg.bgcolor=this.bgcolor;
5321 cfg.border=this.border;
5323 if (this.cellpadding) {
5324 cfg.cellpadding=this.cellpadding;
5326 if (this.cellspacing) {
5327 cfg.cellspacing=this.cellspacing;
5330 cfg.frame=this.frame;
5333 cfg.rules=this.rules;
5335 if (this.sortable) {
5336 cfg.sortable=this.sortable;
5339 cfg.summary=this.summary;
5342 cfg.width=this.width;
5345 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5348 if(this.store || this.cm){
5350 cfg.cn.push(this.renderHeader());
5353 cfg.cn.push(this.renderBody());
5356 cfg.cn.push(this.renderFooter());
5359 cfg.cls+= ' TableGrid';
5362 return { cn : [ cfg ] };
5365 initEvents : function()
5367 if(!this.store || !this.cm){
5371 //Roo.log('initEvents with ds!!!!');
5373 this.mainBody = this.el.select('tbody', true).first();
5378 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5379 e.on('click', _this.sort, _this);
5382 this.el.on("click", this.onClick, this);
5383 this.el.on("dblclick", this.onDblClick, this);
5385 // why is this done????? = it breaks dialogs??
5386 //this.parent().el.setStyle('position', 'relative');
5390 this.footer.parentId = this.id;
5391 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5394 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5396 this.store.on('load', this.onLoad, this);
5397 this.store.on('beforeload', this.onBeforeLoad, this);
5398 this.store.on('update', this.onUpdate, this);
5399 this.store.on('add', this.onAdd, this);
5403 onMouseover : function(e, el)
5405 var cell = Roo.get(el);
5411 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5412 cell = cell.findParent('td', false, true);
5415 var row = cell.findParent('tr', false, true);
5416 var cellIndex = cell.dom.cellIndex;
5417 var rowIndex = row.dom.rowIndex - 1; // start from 0
5419 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5423 onMouseout : function(e, el)
5425 var cell = Roo.get(el);
5431 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5432 cell = cell.findParent('td', false, true);
5435 var row = cell.findParent('tr', false, true);
5436 var cellIndex = cell.dom.cellIndex;
5437 var rowIndex = row.dom.rowIndex - 1; // start from 0
5439 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5443 onClick : function(e, el)
5445 var cell = Roo.get(el);
5447 if(!cell || (!this.CellSelection && !this.RowSelection)){
5451 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5452 cell = cell.findParent('td', false, true);
5455 if(!cell || typeof(cell) == 'undefined'){
5459 var row = cell.findParent('tr', false, true);
5461 if(!row || typeof(row) == 'undefined'){
5465 var cellIndex = cell.dom.cellIndex;
5466 var rowIndex = this.getRowIndex(row);
5468 if(this.CellSelection){
5469 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5472 if(this.RowSelection){
5473 this.fireEvent('rowclick', this, row, rowIndex, e);
5479 onDblClick : function(e,el)
5481 var cell = Roo.get(el);
5483 if(!cell || (!this.CellSelection && !this.RowSelection)){
5487 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5488 cell = cell.findParent('td', false, true);
5491 if(!cell || typeof(cell) == 'undefined'){
5495 var row = cell.findParent('tr', false, true);
5497 if(!row || typeof(row) == 'undefined'){
5501 var cellIndex = cell.dom.cellIndex;
5502 var rowIndex = this.getRowIndex(row);
5504 if(this.CellSelection){
5505 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5508 if(this.RowSelection){
5509 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5513 sort : function(e,el)
5515 var col = Roo.get(el);
5517 if(!col.hasClass('sortable')){
5521 var sort = col.attr('sort');
5524 if(col.hasClass('glyphicon-arrow-up')){
5528 this.store.sortInfo = {field : sort, direction : dir};
5531 Roo.log("calling footer first");
5532 this.footer.onClick('first');
5535 this.store.load({ params : { start : 0 } });
5539 renderHeader : function()
5548 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5550 var config = cm.config[i];
5555 html: cm.getColumnHeader(i)
5558 if(typeof(config.tooltip) != 'undefined'){
5559 c.tooltip = config.tooltip;
5562 if(typeof(config.colspan) != 'undefined'){
5563 c.colspan = config.colspan;
5566 if(typeof(config.hidden) != 'undefined' && config.hidden){
5567 c.style += ' display:none;';
5570 if(typeof(config.dataIndex) != 'undefined'){
5571 c.sort = config.dataIndex;
5574 if(typeof(config.sortable) != 'undefined' && config.sortable){
5578 if(typeof(config.align) != 'undefined' && config.align.length){
5579 c.style += ' text-align:' + config.align + ';';
5582 if(typeof(config.width) != 'undefined'){
5583 c.style += ' width:' + config.width + 'px;';
5592 renderBody : function()
5602 colspan : this.cm.getColumnCount()
5612 renderFooter : function()
5622 colspan : this.cm.getColumnCount()
5636 Roo.log('ds onload');
5641 var ds = this.store;
5643 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5644 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5646 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5647 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5650 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5651 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5655 var tbody = this.mainBody;
5657 if(ds.getCount() > 0){
5658 ds.data.each(function(d,rowIndex){
5659 var row = this.renderRow(cm, ds, rowIndex);
5661 tbody.createChild(row);
5665 if(row.cellObjects.length){
5666 Roo.each(row.cellObjects, function(r){
5667 _this.renderCellObject(r);
5674 Roo.each(this.el.select('tbody td', true).elements, function(e){
5675 e.on('mouseover', _this.onMouseover, _this);
5678 Roo.each(this.el.select('tbody td', true).elements, function(e){
5679 e.on('mouseout', _this.onMouseout, _this);
5681 this.fireEvent('rowsrendered', this);
5682 //if(this.loadMask){
5683 // this.maskEl.hide();
5688 onUpdate : function(ds,record)
5690 this.refreshRow(record);
5693 onRemove : function(ds, record, index, isUpdate){
5694 if(isUpdate !== true){
5695 this.fireEvent("beforerowremoved", this, index, record);
5697 var bt = this.mainBody.dom;
5699 var rows = this.el.select('tbody > tr', true).elements;
5701 if(typeof(rows[index]) != 'undefined'){
5702 bt.removeChild(rows[index].dom);
5705 // if(bt.rows[index]){
5706 // bt.removeChild(bt.rows[index]);
5709 if(isUpdate !== true){
5710 //this.stripeRows(index);
5711 //this.syncRowHeights(index, index);
5713 this.fireEvent("rowremoved", this, index, record);
5717 onAdd : function(ds, records, rowIndex)
5719 //Roo.log('on Add called');
5720 // - note this does not handle multiple adding very well..
5721 var bt = this.mainBody.dom;
5722 for (var i =0 ; i < records.length;i++) {
5723 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5724 //Roo.log(records[i]);
5725 //Roo.log(this.store.getAt(rowIndex+i));
5726 this.insertRow(this.store, rowIndex + i, false);
5733 refreshRow : function(record){
5734 var ds = this.store, index;
5735 if(typeof record == 'number'){
5737 record = ds.getAt(index);
5739 index = ds.indexOf(record);
5741 this.insertRow(ds, index, true);
5742 this.onRemove(ds, record, index+1, true);
5743 //this.syncRowHeights(index, index);
5745 this.fireEvent("rowupdated", this, index, record);
5748 insertRow : function(dm, rowIndex, isUpdate){
5751 this.fireEvent("beforerowsinserted", this, rowIndex);
5753 //var s = this.getScrollState();
5754 var row = this.renderRow(this.cm, this.store, rowIndex);
5755 // insert before rowIndex..
5756 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5760 if(row.cellObjects.length){
5761 Roo.each(row.cellObjects, function(r){
5762 _this.renderCellObject(r);
5767 this.fireEvent("rowsinserted", this, rowIndex);
5768 //this.syncRowHeights(firstRow, lastRow);
5769 //this.stripeRows(firstRow);
5776 getRowDom : function(rowIndex)
5778 var rows = this.el.select('tbody > tr', true).elements;
5780 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5783 // returns the object tree for a tr..
5786 renderRow : function(cm, ds, rowIndex)
5789 var d = ds.getAt(rowIndex);
5796 var cellObjects = [];
5798 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5799 var config = cm.config[i];
5801 var renderer = cm.getRenderer(i);
5805 if(typeof(renderer) !== 'undefined'){
5806 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5808 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5809 // and are rendered into the cells after the row is rendered - using the id for the element.
5811 if(typeof(value) === 'object'){
5821 rowIndex : rowIndex,
5826 this.fireEvent('rowclass', this, rowcfg);
5830 cls : rowcfg.rowClass,
5832 html: (typeof(value) === 'object') ? '' : value
5839 if(typeof(config.colspan) != 'undefined'){
5840 td.colspan = config.colspan;
5843 if(typeof(config.hidden) != 'undefined' && config.hidden){
5844 td.style += ' display:none;';
5847 if(typeof(config.align) != 'undefined' && config.align.length){
5848 td.style += ' text-align:' + config.align + ';';
5851 if(typeof(config.width) != 'undefined'){
5852 td.style += ' width:' + config.width + 'px;';
5855 if(typeof(config.cursor) != 'undefined'){
5856 td.style += ' cursor:' + config.cursor + ';';
5863 row.cellObjects = cellObjects;
5871 onBeforeLoad : function()
5873 //Roo.log('ds onBeforeLoad');
5877 //if(this.loadMask){
5878 // this.maskEl.show();
5886 this.el.select('tbody', true).first().dom.innerHTML = '';
5889 * Show or hide a row.
5890 * @param {Number} rowIndex to show or hide
5891 * @param {Boolean} state hide
5893 setRowVisibility : function(rowIndex, state)
5895 var bt = this.mainBody.dom;
5897 var rows = this.el.select('tbody > tr', true).elements;
5899 if(typeof(rows[rowIndex]) == 'undefined'){
5902 rows[rowIndex].dom.style.display = state ? '' : 'none';
5906 getSelectionModel : function(){
5908 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5910 return this.selModel;
5913 * Render the Roo.bootstrap object from renderder
5915 renderCellObject : function(r)
5919 var t = r.cfg.render(r.container);
5922 Roo.each(r.cfg.cn, function(c){
5924 container: t.getChildContainer(),
5927 _this.renderCellObject(child);
5932 getRowIndex : function(row)
5936 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5959 * @class Roo.bootstrap.TableCell
5960 * @extends Roo.bootstrap.Component
5961 * Bootstrap TableCell class
5962 * @cfg {String} html cell contain text
5963 * @cfg {String} cls cell class
5964 * @cfg {String} tag cell tag (td|th) default td
5965 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5966 * @cfg {String} align Aligns the content in a cell
5967 * @cfg {String} axis Categorizes cells
5968 * @cfg {String} bgcolor Specifies the background color of a cell
5969 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5970 * @cfg {Number} colspan Specifies the number of columns a cell should span
5971 * @cfg {String} headers Specifies one or more header cells a cell is related to
5972 * @cfg {Number} height Sets the height of a cell
5973 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5974 * @cfg {Number} rowspan Sets the number of rows a cell should span
5975 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5976 * @cfg {String} valign Vertical aligns the content in a cell
5977 * @cfg {Number} width Specifies the width of a cell
5980 * Create a new TableCell
5981 * @param {Object} config The config object
5984 Roo.bootstrap.TableCell = function(config){
5985 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5988 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6008 getAutoCreate : function(){
6009 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6029 cfg.align=this.align
6035 cfg.bgcolor=this.bgcolor
6038 cfg.charoff=this.charoff
6041 cfg.colspan=this.colspan
6044 cfg.headers=this.headers
6047 cfg.height=this.height
6050 cfg.nowrap=this.nowrap
6053 cfg.rowspan=this.rowspan
6056 cfg.scope=this.scope
6059 cfg.valign=this.valign
6062 cfg.width=this.width
6081 * @class Roo.bootstrap.TableRow
6082 * @extends Roo.bootstrap.Component
6083 * Bootstrap TableRow class
6084 * @cfg {String} cls row class
6085 * @cfg {String} align Aligns the content in a table row
6086 * @cfg {String} bgcolor Specifies a background color for a table row
6087 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6088 * @cfg {String} valign Vertical aligns the content in a table row
6091 * Create a new TableRow
6092 * @param {Object} config The config object
6095 Roo.bootstrap.TableRow = function(config){
6096 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6099 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6107 getAutoCreate : function(){
6108 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6118 cfg.align = this.align;
6121 cfg.bgcolor = this.bgcolor;
6124 cfg.charoff = this.charoff;
6127 cfg.valign = this.valign;
6145 * @class Roo.bootstrap.TableBody
6146 * @extends Roo.bootstrap.Component
6147 * Bootstrap TableBody class
6148 * @cfg {String} cls element class
6149 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6150 * @cfg {String} align Aligns the content inside the element
6151 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6152 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6155 * Create a new TableBody
6156 * @param {Object} config The config object
6159 Roo.bootstrap.TableBody = function(config){
6160 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6163 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6171 getAutoCreate : function(){
6172 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6186 cfg.align = this.align;
6189 cfg.charoff = this.charoff;
6192 cfg.valign = this.valign;
6199 // initEvents : function()
6206 // this.store = Roo.factory(this.store, Roo.data);
6207 // this.store.on('load', this.onLoad, this);
6209 // this.store.load();
6213 // onLoad: function ()
6215 // this.fireEvent('load', this);
6225 * Ext JS Library 1.1.1
6226 * Copyright(c) 2006-2007, Ext JS, LLC.
6228 * Originally Released Under LGPL - original licence link has changed is not relivant.
6231 * <script type="text/javascript">
6234 // as we use this in bootstrap.
6235 Roo.namespace('Roo.form');
6237 * @class Roo.form.Action
6238 * Internal Class used to handle form actions
6240 * @param {Roo.form.BasicForm} el The form element or its id
6241 * @param {Object} config Configuration options
6246 // define the action interface
6247 Roo.form.Action = function(form, options){
6249 this.options = options || {};
6252 * Client Validation Failed
6255 Roo.form.Action.CLIENT_INVALID = 'client';
6257 * Server Validation Failed
6260 Roo.form.Action.SERVER_INVALID = 'server';
6262 * Connect to Server Failed
6265 Roo.form.Action.CONNECT_FAILURE = 'connect';
6267 * Reading Data from Server Failed
6270 Roo.form.Action.LOAD_FAILURE = 'load';
6272 Roo.form.Action.prototype = {
6274 failureType : undefined,
6275 response : undefined,
6279 run : function(options){
6284 success : function(response){
6289 handleResponse : function(response){
6293 // default connection failure
6294 failure : function(response){
6296 this.response = response;
6297 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6298 this.form.afterAction(this, false);
6301 processResponse : function(response){
6302 this.response = response;
6303 if(!response.responseText){
6306 this.result = this.handleResponse(response);
6310 // utility functions used internally
6311 getUrl : function(appendParams){
6312 var url = this.options.url || this.form.url || this.form.el.dom.action;
6314 var p = this.getParams();
6316 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6322 getMethod : function(){
6323 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6326 getParams : function(){
6327 var bp = this.form.baseParams;
6328 var p = this.options.params;
6330 if(typeof p == "object"){
6331 p = Roo.urlEncode(Roo.applyIf(p, bp));
6332 }else if(typeof p == 'string' && bp){
6333 p += '&' + Roo.urlEncode(bp);
6336 p = Roo.urlEncode(bp);
6341 createCallback : function(){
6343 success: this.success,
6344 failure: this.failure,
6346 timeout: (this.form.timeout*1000),
6347 upload: this.form.fileUpload ? this.success : undefined
6352 Roo.form.Action.Submit = function(form, options){
6353 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6356 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6359 haveProgress : false,
6360 uploadComplete : false,
6362 // uploadProgress indicator.
6363 uploadProgress : function()
6365 if (!this.form.progressUrl) {
6369 if (!this.haveProgress) {
6370 Roo.MessageBox.progress("Uploading", "Uploading");
6372 if (this.uploadComplete) {
6373 Roo.MessageBox.hide();
6377 this.haveProgress = true;
6379 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6381 var c = new Roo.data.Connection();
6383 url : this.form.progressUrl,
6388 success : function(req){
6389 //console.log(data);
6393 rdata = Roo.decode(req.responseText)
6395 Roo.log("Invalid data from server..");
6399 if (!rdata || !rdata.success) {
6401 Roo.MessageBox.alert(Roo.encode(rdata));
6404 var data = rdata.data;
6406 if (this.uploadComplete) {
6407 Roo.MessageBox.hide();
6412 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6413 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6416 this.uploadProgress.defer(2000,this);
6419 failure: function(data) {
6420 Roo.log('progress url failed ');
6431 // run get Values on the form, so it syncs any secondary forms.
6432 this.form.getValues();
6434 var o = this.options;
6435 var method = this.getMethod();
6436 var isPost = method == 'POST';
6437 if(o.clientValidation === false || this.form.isValid()){
6439 if (this.form.progressUrl) {
6440 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6441 (new Date() * 1) + '' + Math.random());
6446 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6447 form:this.form.el.dom,
6448 url:this.getUrl(!isPost),
6450 params:isPost ? this.getParams() : null,
6451 isUpload: this.form.fileUpload
6454 this.uploadProgress();
6456 }else if (o.clientValidation !== false){ // client validation failed
6457 this.failureType = Roo.form.Action.CLIENT_INVALID;
6458 this.form.afterAction(this, false);
6462 success : function(response)
6464 this.uploadComplete= true;
6465 if (this.haveProgress) {
6466 Roo.MessageBox.hide();
6470 var result = this.processResponse(response);
6471 if(result === true || result.success){
6472 this.form.afterAction(this, true);
6476 this.form.markInvalid(result.errors);
6477 this.failureType = Roo.form.Action.SERVER_INVALID;
6479 this.form.afterAction(this, false);
6481 failure : function(response)
6483 this.uploadComplete= true;
6484 if (this.haveProgress) {
6485 Roo.MessageBox.hide();
6488 this.response = response;
6489 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6490 this.form.afterAction(this, false);
6493 handleResponse : function(response){
6494 if(this.form.errorReader){
6495 var rs = this.form.errorReader.read(response);
6498 for(var i = 0, len = rs.records.length; i < len; i++) {
6499 var r = rs.records[i];
6503 if(errors.length < 1){
6507 success : rs.success,
6513 ret = Roo.decode(response.responseText);
6517 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6527 Roo.form.Action.Load = function(form, options){
6528 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6529 this.reader = this.form.reader;
6532 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6537 Roo.Ajax.request(Roo.apply(
6538 this.createCallback(), {
6539 method:this.getMethod(),
6540 url:this.getUrl(false),
6541 params:this.getParams()
6545 success : function(response){
6547 var result = this.processResponse(response);
6548 if(result === true || !result.success || !result.data){
6549 this.failureType = Roo.form.Action.LOAD_FAILURE;
6550 this.form.afterAction(this, false);
6553 this.form.clearInvalid();
6554 this.form.setValues(result.data);
6555 this.form.afterAction(this, true);
6558 handleResponse : function(response){
6559 if(this.form.reader){
6560 var rs = this.form.reader.read(response);
6561 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6563 success : rs.success,
6567 return Roo.decode(response.responseText);
6571 Roo.form.Action.ACTION_TYPES = {
6572 'load' : Roo.form.Action.Load,
6573 'submit' : Roo.form.Action.Submit
6582 * @class Roo.bootstrap.Form
6583 * @extends Roo.bootstrap.Component
6584 * Bootstrap Form class
6585 * @cfg {String} method GET | POST (default POST)
6586 * @cfg {String} labelAlign top | left (default top)
6587 * @cfg {String} align left | right - for navbars
6588 * @cfg {Boolean} loadMask load mask when submit (default true)
6593 * @param {Object} config The config object
6597 Roo.bootstrap.Form = function(config){
6598 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6601 * @event clientvalidation
6602 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6603 * @param {Form} this
6604 * @param {Boolean} valid true if the form has passed client-side validation
6606 clientvalidation: true,
6608 * @event beforeaction
6609 * Fires before any action is performed. Return false to cancel the action.
6610 * @param {Form} this
6611 * @param {Action} action The action to be performed
6615 * @event actionfailed
6616 * Fires when an action fails.
6617 * @param {Form} this
6618 * @param {Action} action The action that failed
6620 actionfailed : true,
6622 * @event actioncomplete
6623 * Fires when an action is completed.
6624 * @param {Form} this
6625 * @param {Action} action The action that completed
6627 actioncomplete : true
6632 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6635 * @cfg {String} method
6636 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6641 * The URL to use for form actions if one isn't supplied in the action options.
6644 * @cfg {Boolean} fileUpload
6645 * Set to true if this form is a file upload.
6649 * @cfg {Object} baseParams
6650 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6654 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6658 * @cfg {Sting} align (left|right) for navbar forms
6663 activeAction : null,
6666 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6667 * element by passing it or its id or mask the form itself by passing in true.
6670 waitMsgTarget : false,
6674 getAutoCreate : function(){
6678 method : this.method || 'POST',
6679 id : this.id || Roo.id(),
6682 if (this.parent().xtype.match(/^Nav/)) {
6683 cfg.cls = 'navbar-form navbar-' + this.align;
6687 if (this.labelAlign == 'left' ) {
6688 cfg.cls += ' form-horizontal';
6694 initEvents : function()
6696 this.el.on('submit', this.onSubmit, this);
6697 // this was added as random key presses on the form where triggering form submit.
6698 this.el.on('keypress', function(e) {
6699 if (e.getCharCode() != 13) {
6702 // we might need to allow it for textareas.. and some other items.
6703 // check e.getTarget().
6705 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6709 Roo.log("keypress blocked");
6717 onSubmit : function(e){
6722 * Returns true if client-side validation on the form is successful.
6725 isValid : function(){
6726 var items = this.getItems();
6728 items.each(function(f){
6737 * Returns true if any fields in this form have changed since their original load.
6740 isDirty : function(){
6742 var items = this.getItems();
6743 items.each(function(f){
6753 * Performs a predefined action (submit or load) or custom actions you define on this form.
6754 * @param {String} actionName The name of the action type
6755 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6756 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6757 * accept other config options):
6759 Property Type Description
6760 ---------------- --------------- ----------------------------------------------------------------------------------
6761 url String The url for the action (defaults to the form's url)
6762 method String The form method to use (defaults to the form's method, or POST if not defined)
6763 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6764 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6765 validate the form on the client (defaults to false)
6767 * @return {BasicForm} this
6769 doAction : function(action, options){
6770 if(typeof action == 'string'){
6771 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6773 if(this.fireEvent('beforeaction', this, action) !== false){
6774 this.beforeAction(action);
6775 action.run.defer(100, action);
6781 beforeAction : function(action){
6782 var o = action.options;
6785 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6787 // not really supported yet.. ??
6789 //if(this.waitMsgTarget === true){
6790 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6791 //}else if(this.waitMsgTarget){
6792 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6793 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6795 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6801 afterAction : function(action, success){
6802 this.activeAction = null;
6803 var o = action.options;
6805 //if(this.waitMsgTarget === true){
6807 //}else if(this.waitMsgTarget){
6808 // this.waitMsgTarget.unmask();
6810 // Roo.MessageBox.updateProgress(1);
6811 // Roo.MessageBox.hide();
6818 Roo.callback(o.success, o.scope, [this, action]);
6819 this.fireEvent('actioncomplete', this, action);
6823 // failure condition..
6824 // we have a scenario where updates need confirming.
6825 // eg. if a locking scenario exists..
6826 // we look for { errors : { needs_confirm : true }} in the response.
6828 (typeof(action.result) != 'undefined') &&
6829 (typeof(action.result.errors) != 'undefined') &&
6830 (typeof(action.result.errors.needs_confirm) != 'undefined')
6833 Roo.log("not supported yet");
6836 Roo.MessageBox.confirm(
6837 "Change requires confirmation",
6838 action.result.errorMsg,
6843 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6853 Roo.callback(o.failure, o.scope, [this, action]);
6854 // show an error message if no failed handler is set..
6855 if (!this.hasListener('actionfailed')) {
6856 Roo.log("need to add dialog support");
6858 Roo.MessageBox.alert("Error",
6859 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6860 action.result.errorMsg :
6861 "Saving Failed, please check your entries or try again"
6866 this.fireEvent('actionfailed', this, action);
6871 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6872 * @param {String} id The value to search for
6875 findField : function(id){
6876 var items = this.getItems();
6877 var field = items.get(id);
6879 items.each(function(f){
6880 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6887 return field || null;
6890 * Mark fields in this form invalid in bulk.
6891 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6892 * @return {BasicForm} this
6894 markInvalid : function(errors){
6895 if(errors instanceof Array){
6896 for(var i = 0, len = errors.length; i < len; i++){
6897 var fieldError = errors[i];
6898 var f = this.findField(fieldError.id);
6900 f.markInvalid(fieldError.msg);
6906 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6907 field.markInvalid(errors[id]);
6911 //Roo.each(this.childForms || [], function (f) {
6912 // f.markInvalid(errors);
6919 * Set values for fields in this form in bulk.
6920 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6921 * @return {BasicForm} this
6923 setValues : function(values){
6924 if(values instanceof Array){ // array of objects
6925 for(var i = 0, len = values.length; i < len; i++){
6927 var f = this.findField(v.id);
6929 f.setValue(v.value);
6930 if(this.trackResetOnLoad){
6931 f.originalValue = f.getValue();
6935 }else{ // object hash
6938 if(typeof values[id] != 'function' && (field = this.findField(id))){
6940 if (field.setFromData &&
6942 field.displayField &&
6943 // combos' with local stores can
6944 // be queried via setValue()
6945 // to set their value..
6946 (field.store && !field.store.isLocal)
6950 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6951 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6952 field.setFromData(sd);
6955 field.setValue(values[id]);
6959 if(this.trackResetOnLoad){
6960 field.originalValue = field.getValue();
6966 //Roo.each(this.childForms || [], function (f) {
6967 // f.setValues(values);
6974 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6975 * they are returned as an array.
6976 * @param {Boolean} asString
6979 getValues : function(asString){
6980 //if (this.childForms) {
6981 // copy values from the child forms
6982 // Roo.each(this.childForms, function (f) {
6983 // this.setValues(f.getValues());
6989 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6990 if(asString === true){
6993 return Roo.urlDecode(fs);
6997 * Returns the fields in this form as an object with key/value pairs.
6998 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7001 getFieldValues : function(with_hidden)
7003 var items = this.getItems();
7005 items.each(function(f){
7009 var v = f.getValue();
7010 if (f.inputType =='radio') {
7011 if (typeof(ret[f.getName()]) == 'undefined') {
7012 ret[f.getName()] = ''; // empty..
7015 if (!f.el.dom.checked) {
7023 // not sure if this supported any more..
7024 if ((typeof(v) == 'object') && f.getRawValue) {
7025 v = f.getRawValue() ; // dates..
7027 // combo boxes where name != hiddenName...
7028 if (f.name != f.getName()) {
7029 ret[f.name] = f.getRawValue();
7031 ret[f.getName()] = v;
7038 * Clears all invalid messages in this form.
7039 * @return {BasicForm} this
7041 clearInvalid : function(){
7042 var items = this.getItems();
7044 items.each(function(f){
7055 * @return {BasicForm} this
7058 var items = this.getItems();
7059 items.each(function(f){
7063 Roo.each(this.childForms || [], function (f) {
7070 getItems : function()
7072 var r=new Roo.util.MixedCollection(false, function(o){
7073 return o.id || (o.id = Roo.id());
7075 var iter = function(el) {
7082 Roo.each(el.items,function(e) {
7102 * Ext JS Library 1.1.1
7103 * Copyright(c) 2006-2007, Ext JS, LLC.
7105 * Originally Released Under LGPL - original licence link has changed is not relivant.
7108 * <script type="text/javascript">
7111 * @class Roo.form.VTypes
7112 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7115 Roo.form.VTypes = function(){
7116 // closure these in so they are only created once.
7117 var alpha = /^[a-zA-Z_]+$/;
7118 var alphanum = /^[a-zA-Z0-9_]+$/;
7119 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7120 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7122 // All these messages and functions are configurable
7125 * The function used to validate email addresses
7126 * @param {String} value The email address
7128 'email' : function(v){
7129 return email.test(v);
7132 * The error text to display when the email validation function returns false
7135 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7137 * The keystroke filter mask to be applied on email input
7140 'emailMask' : /[a-z0-9_\.\-@]/i,
7143 * The function used to validate URLs
7144 * @param {String} value The URL
7146 'url' : function(v){
7150 * The error text to display when the url validation function returns false
7153 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7156 * The function used to validate alpha values
7157 * @param {String} value The value
7159 'alpha' : function(v){
7160 return alpha.test(v);
7163 * The error text to display when the alpha validation function returns false
7166 'alphaText' : 'This field should only contain letters and _',
7168 * The keystroke filter mask to be applied on alpha input
7171 'alphaMask' : /[a-z_]/i,
7174 * The function used to validate alphanumeric values
7175 * @param {String} value The value
7177 'alphanum' : function(v){
7178 return alphanum.test(v);
7181 * The error text to display when the alphanumeric validation function returns false
7184 'alphanumText' : 'This field should only contain letters, numbers and _',
7186 * The keystroke filter mask to be applied on alphanumeric input
7189 'alphanumMask' : /[a-z0-9_]/i
7199 * @class Roo.bootstrap.Input
7200 * @extends Roo.bootstrap.Component
7201 * Bootstrap Input class
7202 * @cfg {Boolean} disabled is it disabled
7203 * @cfg {String} fieldLabel - the label associated
7204 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7205 * @cfg {String} name name of the input
7206 * @cfg {string} fieldLabel - the label associated
7207 * @cfg {string} inputType - input / file submit ...
7208 * @cfg {string} placeholder - placeholder to put in text.
7209 * @cfg {string} before - input group add on before
7210 * @cfg {string} after - input group add on after
7211 * @cfg {string} size - (lg|sm) or leave empty..
7212 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7213 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7214 * @cfg {Number} md colspan out of 12 for computer-sized screens
7215 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7216 * @cfg {string} value default value of the input
7217 * @cfg {Number} labelWidth set the width of label (0-12)
7218 * @cfg {String} labelAlign (top|left)
7219 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7220 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7222 * @cfg {String} align (left|center|right) Default left
7227 * Create a new Input
7228 * @param {Object} config The config object
7231 Roo.bootstrap.Input = function(config){
7232 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7237 * Fires when this field receives input focus.
7238 * @param {Roo.form.Field} this
7243 * Fires when this field loses input focus.
7244 * @param {Roo.form.Field} this
7249 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7250 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7251 * @param {Roo.form.Field} this
7252 * @param {Roo.EventObject} e The event object
7257 * Fires just before the field blurs if the field value has changed.
7258 * @param {Roo.form.Field} this
7259 * @param {Mixed} newValue The new value
7260 * @param {Mixed} oldValue The original value
7265 * Fires after the field has been marked as invalid.
7266 * @param {Roo.form.Field} this
7267 * @param {String} msg The validation message
7272 * Fires after the field has been validated with no errors.
7273 * @param {Roo.form.Field} this
7278 * Fires after the key up
7279 * @param {Roo.form.Field} this
7280 * @param {Roo.EventObject} e The event Object
7286 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7288 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7289 automatic validation (defaults to "keyup").
7291 validationEvent : "keyup",
7293 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7295 validateOnBlur : true,
7297 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7299 validationDelay : 250,
7301 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7303 focusClass : "x-form-focus", // not needed???
7307 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7309 invalidClass : "has-warning",
7312 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7314 validClass : "has-success",
7317 * @cfg {Boolean} hasFeedback (true|false) default true
7322 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7324 invalidFeedbackClass : "glyphicon-warning-sign",
7327 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7329 validFeedbackClass : "glyphicon-ok",
7332 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7334 selectOnFocus : false,
7337 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7341 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7346 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7348 disableKeyFilter : false,
7351 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7355 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7359 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7361 blankText : "This field is required",
7364 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7368 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7370 maxLength : Number.MAX_VALUE,
7372 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7374 minLengthText : "The minimum length for this field is {0}",
7376 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7378 maxLengthText : "The maximum length for this field is {0}",
7382 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7383 * If available, this function will be called only after the basic validators all return true, and will be passed the
7384 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7388 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7389 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7390 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7394 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7398 autocomplete: false,
7417 formatedValue : false,
7419 parentLabelAlign : function()
7422 while (parent.parent()) {
7423 parent = parent.parent();
7424 if (typeof(parent.labelAlign) !='undefined') {
7425 return parent.labelAlign;
7432 getAutoCreate : function(){
7434 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7440 if(this.inputType != 'hidden'){
7441 cfg.cls = 'form-group' //input-group
7447 type : this.inputType,
7449 cls : 'form-control',
7450 placeholder : this.placeholder || '',
7451 autocomplete : this.autocomplete || 'new-password'
7456 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7459 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7460 input.maxLength = this.maxLength;
7463 if (this.disabled) {
7464 input.disabled=true;
7467 if (this.readOnly) {
7468 input.readonly=true;
7472 input.name = this.name;
7475 input.cls += ' input-' + this.size;
7478 ['xs','sm','md','lg'].map(function(size){
7479 if (settings[size]) {
7480 cfg.cls += ' col-' + size + '-' + settings[size];
7484 var inputblock = input;
7488 cls: 'glyphicon form-control-feedback'
7491 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7494 cls : 'has-feedback',
7502 if (this.before || this.after) {
7505 cls : 'input-group',
7509 if (this.before && typeof(this.before) == 'string') {
7511 inputblock.cn.push({
7513 cls : 'roo-input-before input-group-addon',
7517 if (this.before && typeof(this.before) == 'object') {
7518 this.before = Roo.factory(this.before);
7519 Roo.log(this.before);
7520 inputblock.cn.push({
7522 cls : 'roo-input-before input-group-' +
7523 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7527 inputblock.cn.push(input);
7529 if (this.after && typeof(this.after) == 'string') {
7530 inputblock.cn.push({
7532 cls : 'roo-input-after input-group-addon',
7536 if (this.after && typeof(this.after) == 'object') {
7537 this.after = Roo.factory(this.after);
7538 Roo.log(this.after);
7539 inputblock.cn.push({
7541 cls : 'roo-input-after input-group-' +
7542 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7546 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7547 inputblock.cls += ' has-feedback';
7548 inputblock.cn.push(feedback);
7552 if (align ==='left' && this.fieldLabel.length) {
7553 Roo.log("left and has label");
7559 cls : 'control-label col-sm-' + this.labelWidth,
7560 html : this.fieldLabel
7564 cls : "col-sm-" + (12 - this.labelWidth),
7571 } else if ( this.fieldLabel.length) {
7577 //cls : 'input-group-addon',
7578 html : this.fieldLabel
7588 Roo.log(" no label && no align");
7597 Roo.log('input-parentType: ' + this.parentType);
7599 if (this.parentType === 'Navbar' && this.parent().bar) {
7600 cfg.cls += ' navbar-form';
7608 * return the real input element.
7610 inputEl: function ()
7612 return this.el.select('input.form-control',true).first();
7615 tooltipEl : function()
7617 return this.inputEl();
7620 setDisabled : function(v)
7622 var i = this.inputEl().dom;
7624 i.removeAttribute('disabled');
7628 i.setAttribute('disabled','true');
7630 initEvents : function()
7633 this.inputEl().on("keydown" , this.fireKey, this);
7634 this.inputEl().on("focus", this.onFocus, this);
7635 this.inputEl().on("blur", this.onBlur, this);
7637 this.inputEl().relayEvent('keyup', this);
7639 // reference to original value for reset
7640 this.originalValue = this.getValue();
7641 //Roo.form.TextField.superclass.initEvents.call(this);
7642 if(this.validationEvent == 'keyup'){
7643 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7644 this.inputEl().on('keyup', this.filterValidation, this);
7646 else if(this.validationEvent !== false){
7647 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7650 if(this.selectOnFocus){
7651 this.on("focus", this.preFocus, this);
7654 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7655 this.inputEl().on("keypress", this.filterKeys, this);
7658 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7659 this.el.on("click", this.autoSize, this);
7662 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7663 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7666 if (typeof(this.before) == 'object') {
7667 this.before.render(this.el.select('.roo-input-before',true).first());
7669 if (typeof(this.after) == 'object') {
7670 this.after.render(this.el.select('.roo-input-after',true).first());
7675 filterValidation : function(e){
7676 if(!e.isNavKeyPress()){
7677 this.validationTask.delay(this.validationDelay);
7681 * Validates the field value
7682 * @return {Boolean} True if the value is valid, else false
7684 validate : function(){
7685 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7686 if(this.disabled || this.validateValue(this.getRawValue())){
7697 * Validates a value according to the field's validation rules and marks the field as invalid
7698 * if the validation fails
7699 * @param {Mixed} value The value to validate
7700 * @return {Boolean} True if the value is valid, else false
7702 validateValue : function(value){
7703 if(value.length < 1) { // if it's blank
7704 if(this.allowBlank){
7710 if(value.length < this.minLength){
7713 if(value.length > this.maxLength){
7717 var vt = Roo.form.VTypes;
7718 if(!vt[this.vtype](value, this)){
7722 if(typeof this.validator == "function"){
7723 var msg = this.validator(value);
7729 if(this.regex && !this.regex.test(value)){
7739 fireKey : function(e){
7740 //Roo.log('field ' + e.getKey());
7741 if(e.isNavKeyPress()){
7742 this.fireEvent("specialkey", this, e);
7745 focus : function (selectText){
7747 this.inputEl().focus();
7748 if(selectText === true){
7749 this.inputEl().dom.select();
7755 onFocus : function(){
7756 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7757 // this.el.addClass(this.focusClass);
7760 this.hasFocus = true;
7761 this.startValue = this.getValue();
7762 this.fireEvent("focus", this);
7766 beforeBlur : Roo.emptyFn,
7770 onBlur : function(){
7772 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7773 //this.el.removeClass(this.focusClass);
7775 this.hasFocus = false;
7776 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7779 var v = this.getValue();
7780 if(String(v) !== String(this.startValue)){
7781 this.fireEvent('change', this, v, this.startValue);
7783 this.fireEvent("blur", this);
7787 * Resets the current field value to the originally loaded value and clears any validation messages
7790 this.setValue(this.originalValue);
7794 * Returns the name of the field
7795 * @return {Mixed} name The name field
7797 getName: function(){
7801 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7802 * @return {Mixed} value The field value
7804 getValue : function(){
7806 var v = this.inputEl().getValue();
7811 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7812 * @return {Mixed} value The field value
7814 getRawValue : function(){
7815 var v = this.inputEl().getValue();
7821 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7822 * @param {Mixed} value The value to set
7824 setRawValue : function(v){
7825 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7828 selectText : function(start, end){
7829 var v = this.getRawValue();
7831 start = start === undefined ? 0 : start;
7832 end = end === undefined ? v.length : end;
7833 var d = this.inputEl().dom;
7834 if(d.setSelectionRange){
7835 d.setSelectionRange(start, end);
7836 }else if(d.createTextRange){
7837 var range = d.createTextRange();
7838 range.moveStart("character", start);
7839 range.moveEnd("character", v.length-end);
7846 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7847 * @param {Mixed} value The value to set
7849 setValue : function(v){
7852 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7858 processValue : function(value){
7859 if(this.stripCharsRe){
7860 var newValue = value.replace(this.stripCharsRe, '');
7861 if(newValue !== value){
7862 this.setRawValue(newValue);
7869 preFocus : function(){
7871 if(this.selectOnFocus){
7872 this.inputEl().dom.select();
7875 filterKeys : function(e){
7877 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7880 var c = e.getCharCode(), cc = String.fromCharCode(c);
7881 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7884 if(!this.maskRe.test(cc)){
7889 * Clear any invalid styles/messages for this field
7891 clearInvalid : function(){
7893 if(!this.el || this.preventMark){ // not rendered
7896 this.el.removeClass(this.invalidClass);
7898 this.fireEvent('valid', this);
7902 * Mark this field as valid
7904 markValid : function(){
7905 if(!this.el || this.preventMark){ // not rendered
7909 this.el.removeClass([this.invalidClass, this.validClass]);
7911 if(this.disabled || this.allowBlank){
7915 this.el.addClass(this.validClass);
7917 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7919 var feedback = this.el.select('.form-control-feedback', true).first();
7922 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7923 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7928 this.fireEvent('valid', this);
7932 * Mark this field as invalid
7933 * @param {String} msg The validation message
7935 markInvalid : function(msg){
7936 if(!this.el || this.preventMark){ // not rendered
7940 this.el.removeClass([this.invalidClass, this.validClass]);
7942 if(this.disabled || this.allowBlank){
7946 this.el.addClass(this.invalidClass);
7948 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7950 var feedback = this.el.select('.form-control-feedback', true).first();
7953 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7955 if(this.getValue().length){
7956 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7963 this.fireEvent('invalid', this, msg);
7966 SafariOnKeyDown : function(event)
7968 // this is a workaround for a password hang bug on chrome/ webkit.
7970 var isSelectAll = false;
7972 if(this.inputEl().dom.selectionEnd > 0){
7973 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7975 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7976 event.preventDefault();
7981 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7983 event.preventDefault();
7984 // this is very hacky as keydown always get's upper case.
7986 var cc = String.fromCharCode(event.getCharCode());
7987 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7991 adjustWidth : function(tag, w){
7992 tag = tag.toLowerCase();
7993 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7994 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7998 if(tag == 'textarea'){
8001 }else if(Roo.isOpera){
8005 if(tag == 'textarea'){
8024 * @class Roo.bootstrap.TextArea
8025 * @extends Roo.bootstrap.Input
8026 * Bootstrap TextArea class
8027 * @cfg {Number} cols Specifies the visible width of a text area
8028 * @cfg {Number} rows Specifies the visible number of lines in a text area
8029 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8030 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8031 * @cfg {string} html text
8034 * Create a new TextArea
8035 * @param {Object} config The config object
8038 Roo.bootstrap.TextArea = function(config){
8039 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8043 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8053 getAutoCreate : function(){
8055 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8066 value : this.value || '',
8067 html: this.html || '',
8068 cls : 'form-control',
8069 placeholder : this.placeholder || ''
8073 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8074 input.maxLength = this.maxLength;
8078 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8082 input.cols = this.cols;
8085 if (this.readOnly) {
8086 input.readonly = true;
8090 input.name = this.name;
8094 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8098 ['xs','sm','md','lg'].map(function(size){
8099 if (settings[size]) {
8100 cfg.cls += ' col-' + size + '-' + settings[size];
8104 var inputblock = input;
8106 if(this.hasFeedback && !this.allowBlank){
8110 cls: 'glyphicon form-control-feedback'
8114 cls : 'has-feedback',
8123 if (this.before || this.after) {
8126 cls : 'input-group',
8130 inputblock.cn.push({
8132 cls : 'input-group-addon',
8137 inputblock.cn.push(input);
8139 if(this.hasFeedback && !this.allowBlank){
8140 inputblock.cls += ' has-feedback';
8141 inputblock.cn.push(feedback);
8145 inputblock.cn.push({
8147 cls : 'input-group-addon',
8154 if (align ==='left' && this.fieldLabel.length) {
8155 Roo.log("left and has label");
8161 cls : 'control-label col-sm-' + this.labelWidth,
8162 html : this.fieldLabel
8166 cls : "col-sm-" + (12 - this.labelWidth),
8173 } else if ( this.fieldLabel.length) {
8179 //cls : 'input-group-addon',
8180 html : this.fieldLabel
8190 Roo.log(" no label && no align");
8200 if (this.disabled) {
8201 input.disabled=true;
8208 * return the real textarea element.
8210 inputEl: function ()
8212 return this.el.select('textarea.form-control',true).first();
8220 * trigger field - base class for combo..
8225 * @class Roo.bootstrap.TriggerField
8226 * @extends Roo.bootstrap.Input
8227 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8228 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8229 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8230 * for which you can provide a custom implementation. For example:
8232 var trigger = new Roo.bootstrap.TriggerField();
8233 trigger.onTriggerClick = myTriggerFn;
8234 trigger.applyTo('my-field');
8237 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8238 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8239 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8240 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8241 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8244 * Create a new TriggerField.
8245 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8246 * to the base TextField)
8248 Roo.bootstrap.TriggerField = function(config){
8249 this.mimicing = false;
8250 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8253 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8255 * @cfg {String} triggerClass A CSS class to apply to the trigger
8258 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8262 /** @cfg {Boolean} grow @hide */
8263 /** @cfg {Number} growMin @hide */
8264 /** @cfg {Number} growMax @hide */
8270 autoSize: Roo.emptyFn,
8277 actionMode : 'wrap',
8282 getAutoCreate : function(){
8284 var align = this.labelAlign || this.parentLabelAlign();
8289 cls: 'form-group' //input-group
8296 type : this.inputType,
8297 cls : 'form-control',
8298 autocomplete: 'new-password',
8299 placeholder : this.placeholder || ''
8303 input.name = this.name;
8306 input.cls += ' input-' + this.size;
8309 if (this.disabled) {
8310 input.disabled=true;
8313 var inputblock = input;
8315 if(this.hasFeedback && !this.allowBlank){
8319 cls: 'glyphicon form-control-feedback'
8323 cls : 'has-feedback',
8331 if (this.before || this.after) {
8334 cls : 'input-group',
8338 inputblock.cn.push({
8340 cls : 'input-group-addon',
8345 inputblock.cn.push(input);
8347 if(this.hasFeedback && !this.allowBlank){
8348 inputblock.cls += ' has-feedback';
8349 inputblock.cn.push(feedback);
8353 inputblock.cn.push({
8355 cls : 'input-group-addon',
8368 cls: 'form-hidden-field'
8376 Roo.log('multiple');
8384 cls: 'form-hidden-field'
8388 cls: 'select2-choices',
8392 cls: 'select2-search-field',
8405 cls: 'select2-container input-group',
8410 // cls: 'typeahead typeahead-long dropdown-menu',
8411 // style: 'display:none'
8416 if(!this.multiple && this.showToggleBtn){
8422 if (this.caret != false) {
8425 cls: 'fa fa-' + this.caret
8432 cls : 'input-group-addon btn dropdown-toggle',
8437 cls: 'combobox-clear',
8451 combobox.cls += ' select2-container-multi';
8454 if (align ==='left' && this.fieldLabel.length) {
8456 Roo.log("left and has label");
8462 cls : 'control-label col-sm-' + this.labelWidth,
8463 html : this.fieldLabel
8467 cls : "col-sm-" + (12 - this.labelWidth),
8474 } else if ( this.fieldLabel.length) {
8480 //cls : 'input-group-addon',
8481 html : this.fieldLabel
8491 Roo.log(" no label && no align");
8498 ['xs','sm','md','lg'].map(function(size){
8499 if (settings[size]) {
8500 cfg.cls += ' col-' + size + '-' + settings[size];
8511 onResize : function(w, h){
8512 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8513 // if(typeof w == 'number'){
8514 // var x = w - this.trigger.getWidth();
8515 // this.inputEl().setWidth(this.adjustWidth('input', x));
8516 // this.trigger.setStyle('left', x+'px');
8521 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8524 getResizeEl : function(){
8525 return this.inputEl();
8529 getPositionEl : function(){
8530 return this.inputEl();
8534 alignErrorIcon : function(){
8535 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8539 initEvents : function(){
8543 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8544 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8545 if(!this.multiple && this.showToggleBtn){
8546 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8547 if(this.hideTrigger){
8548 this.trigger.setDisplayed(false);
8550 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8554 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8557 //this.trigger.addClassOnOver('x-form-trigger-over');
8558 //this.trigger.addClassOnClick('x-form-trigger-click');
8561 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8565 createList : function()
8567 this.list = Roo.get(document.body).createChild({
8569 cls: 'typeahead typeahead-long dropdown-menu',
8570 style: 'display:none'
8573 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8578 initTrigger : function(){
8583 onDestroy : function(){
8585 this.trigger.removeAllListeners();
8586 // this.trigger.remove();
8589 // this.wrap.remove();
8591 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8595 onFocus : function(){
8596 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8599 this.wrap.addClass('x-trigger-wrap-focus');
8600 this.mimicing = true;
8601 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8602 if(this.monitorTab){
8603 this.el.on("keydown", this.checkTab, this);
8610 checkTab : function(e){
8611 if(e.getKey() == e.TAB){
8617 onBlur : function(){
8622 mimicBlur : function(e, t){
8624 if(!this.wrap.contains(t) && this.validateBlur()){
8631 triggerBlur : function(){
8632 this.mimicing = false;
8633 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8634 if(this.monitorTab){
8635 this.el.un("keydown", this.checkTab, this);
8637 //this.wrap.removeClass('x-trigger-wrap-focus');
8638 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8642 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8643 validateBlur : function(e, t){
8648 onDisable : function(){
8649 this.inputEl().dom.disabled = true;
8650 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8652 // this.wrap.addClass('x-item-disabled');
8657 onEnable : function(){
8658 this.inputEl().dom.disabled = false;
8659 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8661 // this.el.removeClass('x-item-disabled');
8666 onShow : function(){
8667 var ae = this.getActionEl();
8670 ae.dom.style.display = '';
8671 ae.dom.style.visibility = 'visible';
8677 onHide : function(){
8678 var ae = this.getActionEl();
8679 ae.dom.style.display = 'none';
8683 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8684 * by an implementing function.
8686 * @param {EventObject} e
8688 onTriggerClick : Roo.emptyFn
8692 * Ext JS Library 1.1.1
8693 * Copyright(c) 2006-2007, Ext JS, LLC.
8695 * Originally Released Under LGPL - original licence link has changed is not relivant.
8698 * <script type="text/javascript">
8703 * @class Roo.data.SortTypes
8705 * Defines the default sorting (casting?) comparison functions used when sorting data.
8707 Roo.data.SortTypes = {
8709 * Default sort that does nothing
8710 * @param {Mixed} s The value being converted
8711 * @return {Mixed} The comparison value
8718 * The regular expression used to strip tags
8722 stripTagsRE : /<\/?[^>]+>/gi,
8725 * Strips all HTML tags to sort on text only
8726 * @param {Mixed} s The value being converted
8727 * @return {String} The comparison value
8729 asText : function(s){
8730 return String(s).replace(this.stripTagsRE, "");
8734 * Strips all HTML tags to sort on text only - Case insensitive
8735 * @param {Mixed} s The value being converted
8736 * @return {String} The comparison value
8738 asUCText : function(s){
8739 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8743 * Case insensitive string
8744 * @param {Mixed} s The value being converted
8745 * @return {String} The comparison value
8747 asUCString : function(s) {
8748 return String(s).toUpperCase();
8753 * @param {Mixed} s The value being converted
8754 * @return {Number} The comparison value
8756 asDate : function(s) {
8760 if(s instanceof Date){
8763 return Date.parse(String(s));
8768 * @param {Mixed} s The value being converted
8769 * @return {Float} The comparison value
8771 asFloat : function(s) {
8772 var val = parseFloat(String(s).replace(/,/g, ""));
8773 if(isNaN(val)) val = 0;
8779 * @param {Mixed} s The value being converted
8780 * @return {Number} The comparison value
8782 asInt : function(s) {
8783 var val = parseInt(String(s).replace(/,/g, ""));
8784 if(isNaN(val)) val = 0;
8789 * Ext JS Library 1.1.1
8790 * Copyright(c) 2006-2007, Ext JS, LLC.
8792 * Originally Released Under LGPL - original licence link has changed is not relivant.
8795 * <script type="text/javascript">
8799 * @class Roo.data.Record
8800 * Instances of this class encapsulate both record <em>definition</em> information, and record
8801 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8802 * to access Records cached in an {@link Roo.data.Store} object.<br>
8804 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8805 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8808 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8810 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8811 * {@link #create}. The parameters are the same.
8812 * @param {Array} data An associative Array of data values keyed by the field name.
8813 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8814 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8815 * not specified an integer id is generated.
8817 Roo.data.Record = function(data, id){
8818 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8823 * Generate a constructor for a specific record layout.
8824 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8825 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8826 * Each field definition object may contain the following properties: <ul>
8827 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8828 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8829 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8830 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8831 * is being used, then this is a string containing the javascript expression to reference the data relative to
8832 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8833 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8834 * this may be omitted.</p></li>
8835 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8836 * <ul><li>auto (Default, implies no conversion)</li>
8841 * <li>date</li></ul></p></li>
8842 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8843 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8844 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8845 * by the Reader into an object that will be stored in the Record. It is passed the
8846 * following parameters:<ul>
8847 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8849 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8851 * <br>usage:<br><pre><code>
8852 var TopicRecord = Roo.data.Record.create(
8853 {name: 'title', mapping: 'topic_title'},
8854 {name: 'author', mapping: 'username'},
8855 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8856 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8857 {name: 'lastPoster', mapping: 'user2'},
8858 {name: 'excerpt', mapping: 'post_text'}
8861 var myNewRecord = new TopicRecord({
8862 title: 'Do my job please',
8865 lastPost: new Date(),
8866 lastPoster: 'Animal',
8867 excerpt: 'No way dude!'
8869 myStore.add(myNewRecord);
8874 Roo.data.Record.create = function(o){
8876 f.superclass.constructor.apply(this, arguments);
8878 Roo.extend(f, Roo.data.Record);
8879 var p = f.prototype;
8880 p.fields = new Roo.util.MixedCollection(false, function(field){
8883 for(var i = 0, len = o.length; i < len; i++){
8884 p.fields.add(new Roo.data.Field(o[i]));
8886 f.getField = function(name){
8887 return p.fields.get(name);
8892 Roo.data.Record.AUTO_ID = 1000;
8893 Roo.data.Record.EDIT = 'edit';
8894 Roo.data.Record.REJECT = 'reject';
8895 Roo.data.Record.COMMIT = 'commit';
8897 Roo.data.Record.prototype = {
8899 * Readonly flag - true if this record has been modified.
8908 join : function(store){
8913 * Set the named field to the specified value.
8914 * @param {String} name The name of the field to set.
8915 * @param {Object} value The value to set the field to.
8917 set : function(name, value){
8918 if(this.data[name] == value){
8925 if(typeof this.modified[name] == 'undefined'){
8926 this.modified[name] = this.data[name];
8928 this.data[name] = value;
8929 if(!this.editing && this.store){
8930 this.store.afterEdit(this);
8935 * Get the value of the named field.
8936 * @param {String} name The name of the field to get the value of.
8937 * @return {Object} The value of the field.
8939 get : function(name){
8940 return this.data[name];
8944 beginEdit : function(){
8945 this.editing = true;
8950 cancelEdit : function(){
8951 this.editing = false;
8952 delete this.modified;
8956 endEdit : function(){
8957 this.editing = false;
8958 if(this.dirty && this.store){
8959 this.store.afterEdit(this);
8964 * Usually called by the {@link Roo.data.Store} which owns the Record.
8965 * Rejects all changes made to the Record since either creation, or the last commit operation.
8966 * Modified fields are reverted to their original values.
8968 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8969 * of reject operations.
8971 reject : function(){
8972 var m = this.modified;
8974 if(typeof m[n] != "function"){
8975 this.data[n] = m[n];
8979 delete this.modified;
8980 this.editing = false;
8982 this.store.afterReject(this);
8987 * Usually called by the {@link Roo.data.Store} which owns the Record.
8988 * Commits all changes made to the Record since either creation, or the last commit operation.
8990 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8991 * of commit operations.
8993 commit : function(){
8995 delete this.modified;
8996 this.editing = false;
8998 this.store.afterCommit(this);
9003 hasError : function(){
9004 return this.error != null;
9008 clearError : function(){
9013 * Creates a copy of this record.
9014 * @param {String} id (optional) A new record id if you don't want to use this record's id
9017 copy : function(newId) {
9018 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9022 * Ext JS Library 1.1.1
9023 * Copyright(c) 2006-2007, Ext JS, LLC.
9025 * Originally Released Under LGPL - original licence link has changed is not relivant.
9028 * <script type="text/javascript">
9034 * @class Roo.data.Store
9035 * @extends Roo.util.Observable
9036 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9037 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9039 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
9040 * has no knowledge of the format of the data returned by the Proxy.<br>
9042 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9043 * instances from the data object. These records are cached and made available through accessor functions.
9045 * Creates a new Store.
9046 * @param {Object} config A config object containing the objects needed for the Store to access data,
9047 * and read the data into Records.
9049 Roo.data.Store = function(config){
9050 this.data = new Roo.util.MixedCollection(false);
9051 this.data.getKey = function(o){
9054 this.baseParams = {};
9061 "multisort" : "_multisort"
9064 if(config && config.data){
9065 this.inlineData = config.data;
9069 Roo.apply(this, config);
9071 if(this.reader){ // reader passed
9072 this.reader = Roo.factory(this.reader, Roo.data);
9073 this.reader.xmodule = this.xmodule || false;
9074 if(!this.recordType){
9075 this.recordType = this.reader.recordType;
9077 if(this.reader.onMetaChange){
9078 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9082 if(this.recordType){
9083 this.fields = this.recordType.prototype.fields;
9089 * @event datachanged
9090 * Fires when the data cache has changed, and a widget which is using this Store
9091 * as a Record cache should refresh its view.
9092 * @param {Store} this
9097 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9098 * @param {Store} this
9099 * @param {Object} meta The JSON metadata
9104 * Fires when Records have been added to the Store
9105 * @param {Store} this
9106 * @param {Roo.data.Record[]} records The array of Records added
9107 * @param {Number} index The index at which the record(s) were added
9112 * Fires when a Record has been removed from the Store
9113 * @param {Store} this
9114 * @param {Roo.data.Record} record The Record that was removed
9115 * @param {Number} index The index at which the record was removed
9120 * Fires when a Record has been updated
9121 * @param {Store} this
9122 * @param {Roo.data.Record} record The Record that was updated
9123 * @param {String} operation The update operation being performed. Value may be one of:
9125 Roo.data.Record.EDIT
9126 Roo.data.Record.REJECT
9127 Roo.data.Record.COMMIT
9133 * Fires when the data cache has been cleared.
9134 * @param {Store} this
9139 * Fires before a request is made for a new data object. If the beforeload handler returns false
9140 * the load action will be canceled.
9141 * @param {Store} this
9142 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9146 * @event beforeloadadd
9147 * Fires after a new set of Records has been loaded.
9148 * @param {Store} this
9149 * @param {Roo.data.Record[]} records The Records that were loaded
9150 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9152 beforeloadadd : true,
9155 * Fires after a new set of Records has been loaded, before they are added to the store.
9156 * @param {Store} this
9157 * @param {Roo.data.Record[]} records The Records that were loaded
9158 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9159 * @params {Object} return from reader
9163 * @event loadexception
9164 * Fires if an exception occurs in the Proxy during loading.
9165 * Called with the signature of the Proxy's "loadexception" event.
9166 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9169 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9170 * @param {Object} load options
9171 * @param {Object} jsonData from your request (normally this contains the Exception)
9173 loadexception : true
9177 this.proxy = Roo.factory(this.proxy, Roo.data);
9178 this.proxy.xmodule = this.xmodule || false;
9179 this.relayEvents(this.proxy, ["loadexception"]);
9181 this.sortToggle = {};
9182 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9184 Roo.data.Store.superclass.constructor.call(this);
9186 if(this.inlineData){
9187 this.loadData(this.inlineData);
9188 delete this.inlineData;
9192 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9194 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9195 * without a remote query - used by combo/forms at present.
9199 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9202 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9205 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9206 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9209 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9210 * on any HTTP request
9213 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9216 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9220 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9221 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9226 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9227 * loaded or when a record is removed. (defaults to false).
9229 pruneModifiedRecords : false,
9235 * Add Records to the Store and fires the add event.
9236 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9238 add : function(records){
9239 records = [].concat(records);
9240 for(var i = 0, len = records.length; i < len; i++){
9241 records[i].join(this);
9243 var index = this.data.length;
9244 this.data.addAll(records);
9245 this.fireEvent("add", this, records, index);
9249 * Remove a Record from the Store and fires the remove event.
9250 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9252 remove : function(record){
9253 var index = this.data.indexOf(record);
9254 this.data.removeAt(index);
9255 if(this.pruneModifiedRecords){
9256 this.modified.remove(record);
9258 this.fireEvent("remove", this, record, index);
9262 * Remove all Records from the Store and fires the clear event.
9264 removeAll : function(){
9266 if(this.pruneModifiedRecords){
9269 this.fireEvent("clear", this);
9273 * Inserts Records to the Store at the given index and fires the add event.
9274 * @param {Number} index The start index at which to insert the passed Records.
9275 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9277 insert : function(index, records){
9278 records = [].concat(records);
9279 for(var i = 0, len = records.length; i < len; i++){
9280 this.data.insert(index, records[i]);
9281 records[i].join(this);
9283 this.fireEvent("add", this, records, index);
9287 * Get the index within the cache of the passed Record.
9288 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9289 * @return {Number} The index of the passed Record. Returns -1 if not found.
9291 indexOf : function(record){
9292 return this.data.indexOf(record);
9296 * Get the index within the cache of the Record with the passed id.
9297 * @param {String} id The id of the Record to find.
9298 * @return {Number} The index of the Record. Returns -1 if not found.
9300 indexOfId : function(id){
9301 return this.data.indexOfKey(id);
9305 * Get the Record with the specified id.
9306 * @param {String} id The id of the Record to find.
9307 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9309 getById : function(id){
9310 return this.data.key(id);
9314 * Get the Record at the specified index.
9315 * @param {Number} index The index of the Record to find.
9316 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9318 getAt : function(index){
9319 return this.data.itemAt(index);
9323 * Returns a range of Records between specified indices.
9324 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9325 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9326 * @return {Roo.data.Record[]} An array of Records
9328 getRange : function(start, end){
9329 return this.data.getRange(start, end);
9333 storeOptions : function(o){
9334 o = Roo.apply({}, o);
9337 this.lastOptions = o;
9341 * Loads the Record cache from the configured Proxy using the configured Reader.
9343 * If using remote paging, then the first load call must specify the <em>start</em>
9344 * and <em>limit</em> properties in the options.params property to establish the initial
9345 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9347 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9348 * and this call will return before the new data has been loaded. Perform any post-processing
9349 * in a callback function, or in a "load" event handler.</strong>
9351 * @param {Object} options An object containing properties which control loading options:<ul>
9352 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9353 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9354 * passed the following arguments:<ul>
9355 * <li>r : Roo.data.Record[]</li>
9356 * <li>options: Options object from the load call</li>
9357 * <li>success: Boolean success indicator</li></ul></li>
9358 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9359 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9362 load : function(options){
9363 options = options || {};
9364 if(this.fireEvent("beforeload", this, options) !== false){
9365 this.storeOptions(options);
9366 var p = Roo.apply(options.params || {}, this.baseParams);
9367 // if meta was not loaded from remote source.. try requesting it.
9368 if (!this.reader.metaFromRemote) {
9371 if(this.sortInfo && this.remoteSort){
9372 var pn = this.paramNames;
9373 p[pn["sort"]] = this.sortInfo.field;
9374 p[pn["dir"]] = this.sortInfo.direction;
9376 if (this.multiSort) {
9377 var pn = this.paramNames;
9378 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9381 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9386 * Reloads the Record cache from the configured Proxy using the configured Reader and
9387 * the options from the last load operation performed.
9388 * @param {Object} options (optional) An object containing properties which may override the options
9389 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9390 * the most recently used options are reused).
9392 reload : function(options){
9393 this.load(Roo.applyIf(options||{}, this.lastOptions));
9397 // Called as a callback by the Reader during a load operation.
9398 loadRecords : function(o, options, success){
9399 if(!o || success === false){
9400 if(success !== false){
9401 this.fireEvent("load", this, [], options, o);
9403 if(options.callback){
9404 options.callback.call(options.scope || this, [], options, false);
9408 // if data returned failure - throw an exception.
9409 if (o.success === false) {
9410 // show a message if no listener is registered.
9411 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9412 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9414 // loadmask wil be hooked into this..
9415 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9418 var r = o.records, t = o.totalRecords || r.length;
9420 this.fireEvent("beforeloadadd", this, r, options, o);
9422 if(!options || options.add !== true){
9423 if(this.pruneModifiedRecords){
9426 for(var i = 0, len = r.length; i < len; i++){
9430 this.data = this.snapshot;
9431 delete this.snapshot;
9434 this.data.addAll(r);
9435 this.totalLength = t;
9437 this.fireEvent("datachanged", this);
9439 this.totalLength = Math.max(t, this.data.length+r.length);
9442 this.fireEvent("load", this, r, options, o);
9443 if(options.callback){
9444 options.callback.call(options.scope || this, r, options, true);
9450 * Loads data from a passed data block. A Reader which understands the format of the data
9451 * must have been configured in the constructor.
9452 * @param {Object} data The data block from which to read the Records. The format of the data expected
9453 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9454 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9456 loadData : function(o, append){
9457 var r = this.reader.readRecords(o);
9458 this.loadRecords(r, {add: append}, true);
9462 * Gets the number of cached records.
9464 * <em>If using paging, this may not be the total size of the dataset. If the data object
9465 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9466 * the data set size</em>
9468 getCount : function(){
9469 return this.data.length || 0;
9473 * Gets the total number of records in the dataset as returned by the server.
9475 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9476 * the dataset size</em>
9478 getTotalCount : function(){
9479 return this.totalLength || 0;
9483 * Returns the sort state of the Store as an object with two properties:
9485 field {String} The name of the field by which the Records are sorted
9486 direction {String} The sort order, "ASC" or "DESC"
9489 getSortState : function(){
9490 return this.sortInfo;
9494 applySort : function(){
9495 if(this.sortInfo && !this.remoteSort){
9496 var s = this.sortInfo, f = s.field;
9497 var st = this.fields.get(f).sortType;
9498 var fn = function(r1, r2){
9499 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9500 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9502 this.data.sort(s.direction, fn);
9503 if(this.snapshot && this.snapshot != this.data){
9504 this.snapshot.sort(s.direction, fn);
9510 * Sets the default sort column and order to be used by the next load operation.
9511 * @param {String} fieldName The name of the field to sort by.
9512 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9514 setDefaultSort : function(field, dir){
9515 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9520 * If remote sorting is used, the sort is performed on the server, and the cache is
9521 * reloaded. If local sorting is used, the cache is sorted internally.
9522 * @param {String} fieldName The name of the field to sort by.
9523 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9525 sort : function(fieldName, dir){
9526 var f = this.fields.get(fieldName);
9528 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9530 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9531 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9536 this.sortToggle[f.name] = dir;
9537 this.sortInfo = {field: f.name, direction: dir};
9538 if(!this.remoteSort){
9540 this.fireEvent("datachanged", this);
9542 this.load(this.lastOptions);
9547 * Calls the specified function for each of the Records in the cache.
9548 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9549 * Returning <em>false</em> aborts and exits the iteration.
9550 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9552 each : function(fn, scope){
9553 this.data.each(fn, scope);
9557 * Gets all records modified since the last commit. Modified records are persisted across load operations
9558 * (e.g., during paging).
9559 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9561 getModifiedRecords : function(){
9562 return this.modified;
9566 createFilterFn : function(property, value, anyMatch){
9567 if(!value.exec){ // not a regex
9568 value = String(value);
9569 if(value.length == 0){
9572 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9575 return value.test(r.data[property]);
9580 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9581 * @param {String} property A field on your records
9582 * @param {Number} start The record index to start at (defaults to 0)
9583 * @param {Number} end The last record index to include (defaults to length - 1)
9584 * @return {Number} The sum
9586 sum : function(property, start, end){
9587 var rs = this.data.items, v = 0;
9589 end = (end || end === 0) ? end : rs.length-1;
9591 for(var i = start; i <= end; i++){
9592 v += (rs[i].data[property] || 0);
9598 * Filter the records by a specified property.
9599 * @param {String} field A field on your records
9600 * @param {String/RegExp} value Either a string that the field
9601 * should start with or a RegExp to test against the field
9602 * @param {Boolean} anyMatch True to match any part not just the beginning
9604 filter : function(property, value, anyMatch){
9605 var fn = this.createFilterFn(property, value, anyMatch);
9606 return fn ? this.filterBy(fn) : this.clearFilter();
9610 * Filter by a function. The specified function will be called with each
9611 * record in this data source. If the function returns true the record is included,
9612 * otherwise it is filtered.
9613 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9614 * @param {Object} scope (optional) The scope of the function (defaults to this)
9616 filterBy : function(fn, scope){
9617 this.snapshot = this.snapshot || this.data;
9618 this.data = this.queryBy(fn, scope||this);
9619 this.fireEvent("datachanged", this);
9623 * Query the records by a specified property.
9624 * @param {String} field A field on your records
9625 * @param {String/RegExp} value Either a string that the field
9626 * should start with or a RegExp to test against the field
9627 * @param {Boolean} anyMatch True to match any part not just the beginning
9628 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9630 query : function(property, value, anyMatch){
9631 var fn = this.createFilterFn(property, value, anyMatch);
9632 return fn ? this.queryBy(fn) : this.data.clone();
9636 * Query by a function. The specified function will be called with each
9637 * record in this data source. If the function returns true the record is included
9639 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9640 * @param {Object} scope (optional) The scope of the function (defaults to this)
9641 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9643 queryBy : function(fn, scope){
9644 var data = this.snapshot || this.data;
9645 return data.filterBy(fn, scope||this);
9649 * Collects unique values for a particular dataIndex from this store.
9650 * @param {String} dataIndex The property to collect
9651 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9652 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9653 * @return {Array} An array of the unique values
9655 collect : function(dataIndex, allowNull, bypassFilter){
9656 var d = (bypassFilter === true && this.snapshot) ?
9657 this.snapshot.items : this.data.items;
9658 var v, sv, r = [], l = {};
9659 for(var i = 0, len = d.length; i < len; i++){
9660 v = d[i].data[dataIndex];
9662 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9671 * Revert to a view of the Record cache with no filtering applied.
9672 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9674 clearFilter : function(suppressEvent){
9675 if(this.snapshot && this.snapshot != this.data){
9676 this.data = this.snapshot;
9677 delete this.snapshot;
9678 if(suppressEvent !== true){
9679 this.fireEvent("datachanged", this);
9685 afterEdit : function(record){
9686 if(this.modified.indexOf(record) == -1){
9687 this.modified.push(record);
9689 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9693 afterReject : function(record){
9694 this.modified.remove(record);
9695 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9699 afterCommit : function(record){
9700 this.modified.remove(record);
9701 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9705 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9706 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9708 commitChanges : function(){
9709 var m = this.modified.slice(0);
9711 for(var i = 0, len = m.length; i < len; i++){
9717 * Cancel outstanding changes on all changed records.
9719 rejectChanges : function(){
9720 var m = this.modified.slice(0);
9722 for(var i = 0, len = m.length; i < len; i++){
9727 onMetaChange : function(meta, rtype, o){
9728 this.recordType = rtype;
9729 this.fields = rtype.prototype.fields;
9730 delete this.snapshot;
9731 this.sortInfo = meta.sortInfo || this.sortInfo;
9733 this.fireEvent('metachange', this, this.reader.meta);
9736 moveIndex : function(data, type)
9738 var index = this.indexOf(data);
9740 var newIndex = index + type;
9744 this.insert(newIndex, data);
9749 * Ext JS Library 1.1.1
9750 * Copyright(c) 2006-2007, Ext JS, LLC.
9752 * Originally Released Under LGPL - original licence link has changed is not relivant.
9755 * <script type="text/javascript">
9759 * @class Roo.data.SimpleStore
9760 * @extends Roo.data.Store
9761 * Small helper class to make creating Stores from Array data easier.
9762 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9763 * @cfg {Array} fields An array of field definition objects, or field name strings.
9764 * @cfg {Array} data The multi-dimensional array of data
9766 * @param {Object} config
9768 Roo.data.SimpleStore = function(config){
9769 Roo.data.SimpleStore.superclass.constructor.call(this, {
9771 reader: new Roo.data.ArrayReader({
9774 Roo.data.Record.create(config.fields)
9776 proxy : new Roo.data.MemoryProxy(config.data)
9780 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9782 * Ext JS Library 1.1.1
9783 * Copyright(c) 2006-2007, Ext JS, LLC.
9785 * Originally Released Under LGPL - original licence link has changed is not relivant.
9788 * <script type="text/javascript">
9793 * @extends Roo.data.Store
9794 * @class Roo.data.JsonStore
9795 * Small helper class to make creating Stores for JSON data easier. <br/>
9797 var store = new Roo.data.JsonStore({
9798 url: 'get-images.php',
9800 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9803 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9804 * JsonReader and HttpProxy (unless inline data is provided).</b>
9805 * @cfg {Array} fields An array of field definition objects, or field name strings.
9807 * @param {Object} config
9809 Roo.data.JsonStore = function(c){
9810 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9811 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9812 reader: new Roo.data.JsonReader(c, c.fields)
9815 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9817 * Ext JS Library 1.1.1
9818 * Copyright(c) 2006-2007, Ext JS, LLC.
9820 * Originally Released Under LGPL - original licence link has changed is not relivant.
9823 * <script type="text/javascript">
9827 Roo.data.Field = function(config){
9828 if(typeof config == "string"){
9829 config = {name: config};
9831 Roo.apply(this, config);
9837 var st = Roo.data.SortTypes;
9838 // named sortTypes are supported, here we look them up
9839 if(typeof this.sortType == "string"){
9840 this.sortType = st[this.sortType];
9843 // set default sortType for strings and dates
9847 this.sortType = st.asUCString;
9850 this.sortType = st.asDate;
9853 this.sortType = st.none;
9858 var stripRe = /[\$,%]/g;
9860 // prebuilt conversion function for this field, instead of
9861 // switching every time we're reading a value
9863 var cv, dateFormat = this.dateFormat;
9868 cv = function(v){ return v; };
9871 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9875 return v !== undefined && v !== null && v !== '' ?
9876 parseInt(String(v).replace(stripRe, ""), 10) : '';
9881 return v !== undefined && v !== null && v !== '' ?
9882 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9887 cv = function(v){ return v === true || v === "true" || v == 1; };
9894 if(v instanceof Date){
9898 if(dateFormat == "timestamp"){
9899 return new Date(v*1000);
9901 return Date.parseDate(v, dateFormat);
9903 var parsed = Date.parse(v);
9904 return parsed ? new Date(parsed) : null;
9913 Roo.data.Field.prototype = {
9921 * Ext JS Library 1.1.1
9922 * Copyright(c) 2006-2007, Ext JS, LLC.
9924 * Originally Released Under LGPL - original licence link has changed is not relivant.
9927 * <script type="text/javascript">
9930 // Base class for reading structured data from a data source. This class is intended to be
9931 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9934 * @class Roo.data.DataReader
9935 * Base class for reading structured data from a data source. This class is intended to be
9936 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9939 Roo.data.DataReader = function(meta, recordType){
9943 this.recordType = recordType instanceof Array ?
9944 Roo.data.Record.create(recordType) : recordType;
9947 Roo.data.DataReader.prototype = {
9949 * Create an empty record
9950 * @param {Object} data (optional) - overlay some values
9951 * @return {Roo.data.Record} record created.
9953 newRow : function(d) {
9955 this.recordType.prototype.fields.each(function(c) {
9957 case 'int' : da[c.name] = 0; break;
9958 case 'date' : da[c.name] = new Date(); break;
9959 case 'float' : da[c.name] = 0.0; break;
9960 case 'boolean' : da[c.name] = false; break;
9961 default : da[c.name] = ""; break;
9965 return new this.recordType(Roo.apply(da, d));
9970 * Ext JS Library 1.1.1
9971 * Copyright(c) 2006-2007, Ext JS, LLC.
9973 * Originally Released Under LGPL - original licence link has changed is not relivant.
9976 * <script type="text/javascript">
9980 * @class Roo.data.DataProxy
9981 * @extends Roo.data.Observable
9982 * This class is an abstract base class for implementations which provide retrieval of
9983 * unformatted data objects.<br>
9985 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9986 * (of the appropriate type which knows how to parse the data object) to provide a block of
9987 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9989 * Custom implementations must implement the load method as described in
9990 * {@link Roo.data.HttpProxy#load}.
9992 Roo.data.DataProxy = function(){
9996 * Fires before a network request is made to retrieve a data object.
9997 * @param {Object} This DataProxy object.
9998 * @param {Object} params The params parameter to the load function.
10003 * Fires before the load method's callback is called.
10004 * @param {Object} This DataProxy object.
10005 * @param {Object} o The data object.
10006 * @param {Object} arg The callback argument object passed to the load function.
10010 * @event loadexception
10011 * Fires if an Exception occurs during data retrieval.
10012 * @param {Object} This DataProxy object.
10013 * @param {Object} o The data object.
10014 * @param {Object} arg The callback argument object passed to the load function.
10015 * @param {Object} e The Exception.
10017 loadexception : true
10019 Roo.data.DataProxy.superclass.constructor.call(this);
10022 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10025 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10029 * Ext JS Library 1.1.1
10030 * Copyright(c) 2006-2007, Ext JS, LLC.
10032 * Originally Released Under LGPL - original licence link has changed is not relivant.
10035 * <script type="text/javascript">
10038 * @class Roo.data.MemoryProxy
10039 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10040 * to the Reader when its load method is called.
10042 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10044 Roo.data.MemoryProxy = function(data){
10048 Roo.data.MemoryProxy.superclass.constructor.call(this);
10052 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10054 * Load data from the requested source (in this case an in-memory
10055 * data object passed to the constructor), read the data object into
10056 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10057 * process that block using the passed callback.
10058 * @param {Object} params This parameter is not used by the MemoryProxy class.
10059 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10060 * object into a block of Roo.data.Records.
10061 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10062 * The function must be passed <ul>
10063 * <li>The Record block object</li>
10064 * <li>The "arg" argument from the load function</li>
10065 * <li>A boolean success indicator</li>
10067 * @param {Object} scope The scope in which to call the callback
10068 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10070 load : function(params, reader, callback, scope, arg){
10071 params = params || {};
10074 result = reader.readRecords(this.data);
10076 this.fireEvent("loadexception", this, arg, null, e);
10077 callback.call(scope, null, arg, false);
10080 callback.call(scope, result, arg, true);
10084 update : function(params, records){
10089 * Ext JS Library 1.1.1
10090 * Copyright(c) 2006-2007, Ext JS, LLC.
10092 * Originally Released Under LGPL - original licence link has changed is not relivant.
10095 * <script type="text/javascript">
10098 * @class Roo.data.HttpProxy
10099 * @extends Roo.data.DataProxy
10100 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10101 * configured to reference a certain URL.<br><br>
10103 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10104 * from which the running page was served.<br><br>
10106 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10108 * Be aware that to enable the browser to parse an XML document, the server must set
10109 * the Content-Type header in the HTTP response to "text/xml".
10111 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10112 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10113 * will be used to make the request.
10115 Roo.data.HttpProxy = function(conn){
10116 Roo.data.HttpProxy.superclass.constructor.call(this);
10117 // is conn a conn config or a real conn?
10119 this.useAjax = !conn || !conn.events;
10123 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10124 // thse are take from connection...
10127 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10130 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10131 * extra parameters to each request made by this object. (defaults to undefined)
10134 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10135 * to each request made by this object. (defaults to undefined)
10138 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
10141 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10144 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10150 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10154 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10155 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10156 * a finer-grained basis than the DataProxy events.
10158 getConnection : function(){
10159 return this.useAjax ? Roo.Ajax : this.conn;
10163 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10164 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10165 * process that block using the passed callback.
10166 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10167 * for the request to the remote server.
10168 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10169 * object into a block of Roo.data.Records.
10170 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10171 * The function must be passed <ul>
10172 * <li>The Record block object</li>
10173 * <li>The "arg" argument from the load function</li>
10174 * <li>A boolean success indicator</li>
10176 * @param {Object} scope The scope in which to call the callback
10177 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10179 load : function(params, reader, callback, scope, arg){
10180 if(this.fireEvent("beforeload", this, params) !== false){
10182 params : params || {},
10184 callback : callback,
10189 callback : this.loadResponse,
10193 Roo.applyIf(o, this.conn);
10194 if(this.activeRequest){
10195 Roo.Ajax.abort(this.activeRequest);
10197 this.activeRequest = Roo.Ajax.request(o);
10199 this.conn.request(o);
10202 callback.call(scope||this, null, arg, false);
10207 loadResponse : function(o, success, response){
10208 delete this.activeRequest;
10210 this.fireEvent("loadexception", this, o, response);
10211 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10216 result = o.reader.read(response);
10218 this.fireEvent("loadexception", this, o, response, e);
10219 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10223 this.fireEvent("load", this, o, o.request.arg);
10224 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10228 update : function(dataSet){
10233 updateResponse : function(dataSet){
10238 * Ext JS Library 1.1.1
10239 * Copyright(c) 2006-2007, Ext JS, LLC.
10241 * Originally Released Under LGPL - original licence link has changed is not relivant.
10244 * <script type="text/javascript">
10248 * @class Roo.data.ScriptTagProxy
10249 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10250 * other than the originating domain of the running page.<br><br>
10252 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
10253 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10255 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10256 * source code that is used as the source inside a <script> tag.<br><br>
10258 * In order for the browser to process the returned data, the server must wrap the data object
10259 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10260 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10261 * depending on whether the callback name was passed:
10264 boolean scriptTag = false;
10265 String cb = request.getParameter("callback");
10268 response.setContentType("text/javascript");
10270 response.setContentType("application/x-json");
10272 Writer out = response.getWriter();
10274 out.write(cb + "(");
10276 out.print(dataBlock.toJsonString());
10283 * @param {Object} config A configuration object.
10285 Roo.data.ScriptTagProxy = function(config){
10286 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10287 Roo.apply(this, config);
10288 this.head = document.getElementsByTagName("head")[0];
10291 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10293 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10295 * @cfg {String} url The URL from which to request the data object.
10298 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10302 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10303 * the server the name of the callback function set up by the load call to process the returned data object.
10304 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10305 * javascript output which calls this named function passing the data object as its only parameter.
10307 callbackParam : "callback",
10309 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10310 * name to the request.
10315 * Load data from the configured URL, read the data object into
10316 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10317 * process that block using the passed callback.
10318 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10319 * for the request to the remote server.
10320 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10321 * object into a block of Roo.data.Records.
10322 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10323 * The function must be passed <ul>
10324 * <li>The Record block object</li>
10325 * <li>The "arg" argument from the load function</li>
10326 * <li>A boolean success indicator</li>
10328 * @param {Object} scope The scope in which to call the callback
10329 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10331 load : function(params, reader, callback, scope, arg){
10332 if(this.fireEvent("beforeload", this, params) !== false){
10334 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10336 var url = this.url;
10337 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10339 url += "&_dc=" + (new Date().getTime());
10341 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10344 cb : "stcCallback"+transId,
10345 scriptId : "stcScript"+transId,
10349 callback : callback,
10355 window[trans.cb] = function(o){
10356 conn.handleResponse(o, trans);
10359 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10361 if(this.autoAbort !== false){
10365 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10367 var script = document.createElement("script");
10368 script.setAttribute("src", url);
10369 script.setAttribute("type", "text/javascript");
10370 script.setAttribute("id", trans.scriptId);
10371 this.head.appendChild(script);
10373 this.trans = trans;
10375 callback.call(scope||this, null, arg, false);
10380 isLoading : function(){
10381 return this.trans ? true : false;
10385 * Abort the current server request.
10387 abort : function(){
10388 if(this.isLoading()){
10389 this.destroyTrans(this.trans);
10394 destroyTrans : function(trans, isLoaded){
10395 this.head.removeChild(document.getElementById(trans.scriptId));
10396 clearTimeout(trans.timeoutId);
10398 window[trans.cb] = undefined;
10400 delete window[trans.cb];
10403 // if hasn't been loaded, wait for load to remove it to prevent script error
10404 window[trans.cb] = function(){
10405 window[trans.cb] = undefined;
10407 delete window[trans.cb];
10414 handleResponse : function(o, trans){
10415 this.trans = false;
10416 this.destroyTrans(trans, true);
10419 result = trans.reader.readRecords(o);
10421 this.fireEvent("loadexception", this, o, trans.arg, e);
10422 trans.callback.call(trans.scope||window, null, trans.arg, false);
10425 this.fireEvent("load", this, o, trans.arg);
10426 trans.callback.call(trans.scope||window, result, trans.arg, true);
10430 handleFailure : function(trans){
10431 this.trans = false;
10432 this.destroyTrans(trans, false);
10433 this.fireEvent("loadexception", this, null, trans.arg);
10434 trans.callback.call(trans.scope||window, null, trans.arg, false);
10438 * Ext JS Library 1.1.1
10439 * Copyright(c) 2006-2007, Ext JS, LLC.
10441 * Originally Released Under LGPL - original licence link has changed is not relivant.
10444 * <script type="text/javascript">
10448 * @class Roo.data.JsonReader
10449 * @extends Roo.data.DataReader
10450 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10451 * based on mappings in a provided Roo.data.Record constructor.
10453 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10454 * in the reply previously.
10459 var RecordDef = Roo.data.Record.create([
10460 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10461 {name: 'occupation'} // This field will use "occupation" as the mapping.
10463 var myReader = new Roo.data.JsonReader({
10464 totalProperty: "results", // The property which contains the total dataset size (optional)
10465 root: "rows", // The property which contains an Array of row objects
10466 id: "id" // The property within each row object that provides an ID for the record (optional)
10470 * This would consume a JSON file like this:
10472 { 'results': 2, 'rows': [
10473 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10474 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10477 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10478 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10479 * paged from the remote server.
10480 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10481 * @cfg {String} root name of the property which contains the Array of row objects.
10482 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10484 * Create a new JsonReader
10485 * @param {Object} meta Metadata configuration options
10486 * @param {Object} recordType Either an Array of field definition objects,
10487 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10489 Roo.data.JsonReader = function(meta, recordType){
10492 // set some defaults:
10493 Roo.applyIf(meta, {
10494 totalProperty: 'total',
10495 successProperty : 'success',
10500 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10502 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10505 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10506 * Used by Store query builder to append _requestMeta to params.
10509 metaFromRemote : false,
10511 * This method is only used by a DataProxy which has retrieved data from a remote server.
10512 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10513 * @return {Object} data A data block which is used by an Roo.data.Store object as
10514 * a cache of Roo.data.Records.
10516 read : function(response){
10517 var json = response.responseText;
10519 var o = /* eval:var:o */ eval("("+json+")");
10521 throw {message: "JsonReader.read: Json object not found"};
10527 this.metaFromRemote = true;
10528 this.meta = o.metaData;
10529 this.recordType = Roo.data.Record.create(o.metaData.fields);
10530 this.onMetaChange(this.meta, this.recordType, o);
10532 return this.readRecords(o);
10535 // private function a store will implement
10536 onMetaChange : function(meta, recordType, o){
10543 simpleAccess: function(obj, subsc) {
10550 getJsonAccessor: function(){
10552 return function(expr) {
10554 return(re.test(expr))
10555 ? new Function("obj", "return obj." + expr)
10560 return Roo.emptyFn;
10565 * Create a data block containing Roo.data.Records from an XML document.
10566 * @param {Object} o An object which contains an Array of row objects in the property specified
10567 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10568 * which contains the total size of the dataset.
10569 * @return {Object} data A data block which is used by an Roo.data.Store object as
10570 * a cache of Roo.data.Records.
10572 readRecords : function(o){
10574 * After any data loads, the raw JSON data is available for further custom processing.
10578 var s = this.meta, Record = this.recordType,
10579 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10581 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10583 if(s.totalProperty) {
10584 this.getTotal = this.getJsonAccessor(s.totalProperty);
10586 if(s.successProperty) {
10587 this.getSuccess = this.getJsonAccessor(s.successProperty);
10589 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10591 var g = this.getJsonAccessor(s.id);
10592 this.getId = function(rec) {
10594 return (r === undefined || r === "") ? null : r;
10597 this.getId = function(){return null;};
10600 for(var jj = 0; jj < fl; jj++){
10602 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10603 this.ef[jj] = this.getJsonAccessor(map);
10607 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10608 if(s.totalProperty){
10609 var vt = parseInt(this.getTotal(o), 10);
10614 if(s.successProperty){
10615 var vs = this.getSuccess(o);
10616 if(vs === false || vs === 'false'){
10621 for(var i = 0; i < c; i++){
10624 var id = this.getId(n);
10625 for(var j = 0; j < fl; j++){
10627 var v = this.ef[j](n);
10629 Roo.log('missing convert for ' + f.name);
10633 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10635 var record = new Record(values, id);
10637 records[i] = record;
10643 totalRecords : totalRecords
10648 * Ext JS Library 1.1.1
10649 * Copyright(c) 2006-2007, Ext JS, LLC.
10651 * Originally Released Under LGPL - original licence link has changed is not relivant.
10654 * <script type="text/javascript">
10658 * @class Roo.data.ArrayReader
10659 * @extends Roo.data.DataReader
10660 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10661 * Each element of that Array represents a row of data fields. The
10662 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10663 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10667 var RecordDef = Roo.data.Record.create([
10668 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10669 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10671 var myReader = new Roo.data.ArrayReader({
10672 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10676 * This would consume an Array like this:
10678 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10680 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10682 * Create a new JsonReader
10683 * @param {Object} meta Metadata configuration options.
10684 * @param {Object} recordType Either an Array of field definition objects
10685 * as specified to {@link Roo.data.Record#create},
10686 * or an {@link Roo.data.Record} object
10687 * created using {@link Roo.data.Record#create}.
10689 Roo.data.ArrayReader = function(meta, recordType){
10690 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10693 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10695 * Create a data block containing Roo.data.Records from an XML document.
10696 * @param {Object} o An Array of row objects which represents the dataset.
10697 * @return {Object} data A data block which is used by an Roo.data.Store object as
10698 * a cache of Roo.data.Records.
10700 readRecords : function(o){
10701 var sid = this.meta ? this.meta.id : null;
10702 var recordType = this.recordType, fields = recordType.prototype.fields;
10705 for(var i = 0; i < root.length; i++){
10708 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10709 for(var j = 0, jlen = fields.length; j < jlen; j++){
10710 var f = fields.items[j];
10711 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10712 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10714 values[f.name] = v;
10716 var record = new recordType(values, id);
10718 records[records.length] = record;
10722 totalRecords : records.length
10731 * @class Roo.bootstrap.ComboBox
10732 * @extends Roo.bootstrap.TriggerField
10733 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10734 * @cfg {Boolean} append (true|false) default false
10735 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10736 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10737 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10738 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10739 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10741 * Create a new ComboBox.
10742 * @param {Object} config Configuration options
10744 Roo.bootstrap.ComboBox = function(config){
10745 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10749 * Fires when the dropdown list is expanded
10750 * @param {Roo.bootstrap.ComboBox} combo This combo box
10755 * Fires when the dropdown list is collapsed
10756 * @param {Roo.bootstrap.ComboBox} combo This combo box
10760 * @event beforeselect
10761 * Fires before a list item is selected. Return false to cancel the selection.
10762 * @param {Roo.bootstrap.ComboBox} combo This combo box
10763 * @param {Roo.data.Record} record The data record returned from the underlying store
10764 * @param {Number} index The index of the selected item in the dropdown list
10766 'beforeselect' : true,
10769 * Fires when a list item is selected
10770 * @param {Roo.bootstrap.ComboBox} combo This combo box
10771 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10772 * @param {Number} index The index of the selected item in the dropdown list
10776 * @event beforequery
10777 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10778 * The event object passed has these properties:
10779 * @param {Roo.bootstrap.ComboBox} combo This combo box
10780 * @param {String} query The query
10781 * @param {Boolean} forceAll true to force "all" query
10782 * @param {Boolean} cancel true to cancel the query
10783 * @param {Object} e The query event object
10785 'beforequery': true,
10788 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10789 * @param {Roo.bootstrap.ComboBox} combo This combo box
10794 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10795 * @param {Roo.bootstrap.ComboBox} combo This combo box
10796 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10801 * Fires when the remove value from the combobox array
10802 * @param {Roo.bootstrap.ComboBox} combo This combo box
10806 * @event specialfilter
10807 * Fires when specialfilter
10808 * @param {Roo.bootstrap.ComboBox} combo This combo box
10810 'specialfilter' : true
10815 this.tickItems = [];
10817 this.selectedIndex = -1;
10818 if(this.mode == 'local'){
10819 if(config.queryDelay === undefined){
10820 this.queryDelay = 10;
10822 if(config.minChars === undefined){
10828 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10831 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10832 * rendering into an Roo.Editor, defaults to false)
10835 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10836 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10839 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10842 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10843 * the dropdown list (defaults to undefined, with no header element)
10847 * @cfg {String/Roo.Template} tpl The template to use to render the output
10851 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10853 listWidth: undefined,
10855 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10856 * mode = 'remote' or 'text' if mode = 'local')
10858 displayField: undefined,
10861 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10862 * mode = 'remote' or 'value' if mode = 'local').
10863 * Note: use of a valueField requires the user make a selection
10864 * in order for a value to be mapped.
10866 valueField: undefined,
10870 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10871 * field's data value (defaults to the underlying DOM element's name)
10873 hiddenName: undefined,
10875 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10879 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10881 selectedClass: 'active',
10884 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10888 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10889 * anchor positions (defaults to 'tl-bl')
10891 listAlign: 'tl-bl?',
10893 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10897 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10898 * query specified by the allQuery config option (defaults to 'query')
10900 triggerAction: 'query',
10902 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10903 * (defaults to 4, does not apply if editable = false)
10907 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10908 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10912 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10913 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10917 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10918 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10922 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10923 * when editable = true (defaults to false)
10925 selectOnFocus:false,
10927 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10929 queryParam: 'query',
10931 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10932 * when mode = 'remote' (defaults to 'Loading...')
10934 loadingText: 'Loading...',
10936 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10940 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10944 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10945 * traditional select (defaults to true)
10949 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10953 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10957 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10958 * listWidth has a higher value)
10962 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10963 * allow the user to set arbitrary text into the field (defaults to false)
10965 forceSelection:false,
10967 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10968 * if typeAhead = true (defaults to 250)
10970 typeAheadDelay : 250,
10972 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10973 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10975 valueNotFoundText : undefined,
10977 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10979 blockFocus : false,
10982 * @cfg {Boolean} disableClear Disable showing of clear button.
10984 disableClear : false,
10986 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10988 alwaysQuery : false,
10991 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10996 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10998 invalidClass : "has-warning",
11001 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11003 validClass : "has-success",
11006 * @cfg {Boolean} specialFilter (true|false) special filter default false
11008 specialFilter : false,
11020 btnPosition : 'right',
11021 triggerList : true,
11022 showToggleBtn : true,
11023 // element that contains real text value.. (when hidden is used..)
11025 getAutoCreate : function()
11032 if(!this.tickable){
11033 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11038 * ComboBox with tickable selections
11041 var align = this.labelAlign || this.parentLabelAlign();
11044 cls : 'form-group roo-combobox-tickable' //input-group
11049 cls : 'tickable-buttons',
11054 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11061 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11068 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11075 buttons.cn.unshift({
11077 cls: 'select2-search-field-input'
11083 Roo.each(buttons.cn, function(c){
11085 c.cls += ' btn-' + _this.size;
11088 if (_this.disabled) {
11099 cls: 'form-hidden-field'
11103 cls: 'select2-choices',
11107 cls: 'select2-search-field',
11119 cls: 'select2-container input-group select2-container-multi',
11124 // cls: 'typeahead typeahead-long dropdown-menu',
11125 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11130 if(this.hasFeedback && !this.allowBlank){
11134 cls: 'glyphicon form-control-feedback'
11137 combobox.cn.push(feedback);
11140 if (align ==='left' && this.fieldLabel.length) {
11142 Roo.log("left and has label");
11148 cls : 'control-label col-sm-' + this.labelWidth,
11149 html : this.fieldLabel
11153 cls : "col-sm-" + (12 - this.labelWidth),
11160 } else if ( this.fieldLabel.length) {
11166 //cls : 'input-group-addon',
11167 html : this.fieldLabel
11177 Roo.log(" no label && no align");
11184 ['xs','sm','md','lg'].map(function(size){
11185 if (settings[size]) {
11186 cfg.cls += ' col-' + size + '-' + settings[size];
11195 initEvents: function()
11199 throw "can not find store for combo";
11201 this.store = Roo.factory(this.store, Roo.data);
11204 this.initTickableEvents();
11208 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11210 if(this.hiddenName){
11212 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11214 this.hiddenField.dom.value =
11215 this.hiddenValue !== undefined ? this.hiddenValue :
11216 this.value !== undefined ? this.value : '';
11218 // prevent input submission
11219 this.el.dom.removeAttribute('name');
11220 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11225 // this.el.dom.setAttribute('autocomplete', 'off');
11228 var cls = 'x-combo-list';
11230 //this.list = new Roo.Layer({
11231 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11237 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11238 _this.list.setWidth(lw);
11241 this.list.on('mouseover', this.onViewOver, this);
11242 this.list.on('mousemove', this.onViewMove, this);
11244 this.list.on('scroll', this.onViewScroll, this);
11247 this.list.swallowEvent('mousewheel');
11248 this.assetHeight = 0;
11251 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11252 this.assetHeight += this.header.getHeight();
11255 this.innerList = this.list.createChild({cls:cls+'-inner'});
11256 this.innerList.on('mouseover', this.onViewOver, this);
11257 this.innerList.on('mousemove', this.onViewMove, this);
11258 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11260 if(this.allowBlank && !this.pageSize && !this.disableClear){
11261 this.footer = this.list.createChild({cls:cls+'-ft'});
11262 this.pageTb = new Roo.Toolbar(this.footer);
11266 this.footer = this.list.createChild({cls:cls+'-ft'});
11267 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11268 {pageSize: this.pageSize});
11272 if (this.pageTb && this.allowBlank && !this.disableClear) {
11274 this.pageTb.add(new Roo.Toolbar.Fill(), {
11275 cls: 'x-btn-icon x-btn-clear',
11277 handler: function()
11280 _this.clearValue();
11281 _this.onSelect(false, -1);
11286 this.assetHeight += this.footer.getHeight();
11291 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11294 this.view = new Roo.View(this.list, this.tpl, {
11295 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11297 //this.view.wrapEl.setDisplayed(false);
11298 this.view.on('click', this.onViewClick, this);
11302 this.store.on('beforeload', this.onBeforeLoad, this);
11303 this.store.on('load', this.onLoad, this);
11304 this.store.on('loadexception', this.onLoadException, this);
11306 if(this.resizable){
11307 this.resizer = new Roo.Resizable(this.list, {
11308 pinned:true, handles:'se'
11310 this.resizer.on('resize', function(r, w, h){
11311 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11312 this.listWidth = w;
11313 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11314 this.restrictHeight();
11316 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11319 if(!this.editable){
11320 this.editable = true;
11321 this.setEditable(false);
11326 if (typeof(this.events.add.listeners) != 'undefined') {
11328 this.addicon = this.wrap.createChild(
11329 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11331 this.addicon.on('click', function(e) {
11332 this.fireEvent('add', this);
11335 if (typeof(this.events.edit.listeners) != 'undefined') {
11337 this.editicon = this.wrap.createChild(
11338 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11339 if (this.addicon) {
11340 this.editicon.setStyle('margin-left', '40px');
11342 this.editicon.on('click', function(e) {
11344 // we fire even if inothing is selected..
11345 this.fireEvent('edit', this, this.lastData );
11351 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11352 "up" : function(e){
11353 this.inKeyMode = true;
11357 "down" : function(e){
11358 if(!this.isExpanded()){
11359 this.onTriggerClick();
11361 this.inKeyMode = true;
11366 "enter" : function(e){
11367 // this.onViewClick();
11371 if(this.fireEvent("specialkey", this, e)){
11372 this.onViewClick(false);
11378 "esc" : function(e){
11382 "tab" : function(e){
11385 if(this.fireEvent("specialkey", this, e)){
11386 this.onViewClick(false);
11394 doRelay : function(foo, bar, hname){
11395 if(hname == 'down' || this.scope.isExpanded()){
11396 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11405 this.queryDelay = Math.max(this.queryDelay || 10,
11406 this.mode == 'local' ? 10 : 250);
11409 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11411 if(this.typeAhead){
11412 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11414 if(this.editable !== false){
11415 this.inputEl().on("keyup", this.onKeyUp, this);
11417 if(this.forceSelection){
11418 this.inputEl().on('blur', this.doForce, this);
11422 this.choices = this.el.select('ul.select2-choices', true).first();
11423 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11427 initTickableEvents: function()
11431 if(this.hiddenName){
11433 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11435 this.hiddenField.dom.value =
11436 this.hiddenValue !== undefined ? this.hiddenValue :
11437 this.value !== undefined ? this.value : '';
11439 // prevent input submission
11440 this.el.dom.removeAttribute('name');
11441 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11446 // this.list = this.el.select('ul.dropdown-menu',true).first();
11448 this.choices = this.el.select('ul.select2-choices', true).first();
11449 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11450 if(this.triggerList){
11451 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11454 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11455 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11457 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11458 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11460 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11461 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11463 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11464 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11465 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11468 this.cancelBtn.hide();
11473 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11474 _this.list.setWidth(lw);
11477 this.list.on('mouseover', this.onViewOver, this);
11478 this.list.on('mousemove', this.onViewMove, this);
11480 this.list.on('scroll', this.onViewScroll, this);
11483 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11486 this.view = new Roo.View(this.list, this.tpl, {
11487 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11490 //this.view.wrapEl.setDisplayed(false);
11491 this.view.on('click', this.onViewClick, this);
11495 this.store.on('beforeload', this.onBeforeLoad, this);
11496 this.store.on('load', this.onLoad, this);
11497 this.store.on('loadexception', this.onLoadException, this);
11500 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11501 "up" : function(e){
11502 this.inKeyMode = true;
11506 "down" : function(e){
11507 this.inKeyMode = true;
11511 "enter" : function(e){
11512 if(this.fireEvent("specialkey", this, e)){
11513 this.onViewClick(false);
11519 "esc" : function(e){
11520 this.onTickableFooterButtonClick(e, false, false);
11523 "tab" : function(e){
11524 this.fireEvent("specialkey", this, e);
11526 this.onTickableFooterButtonClick(e, false, false);
11533 doRelay : function(e, fn, key){
11534 if(this.scope.isExpanded()){
11535 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11544 this.queryDelay = Math.max(this.queryDelay || 10,
11545 this.mode == 'local' ? 10 : 250);
11548 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11550 if(this.typeAhead){
11551 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11554 if(this.editable !== false){
11555 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11560 onDestroy : function(){
11562 this.view.setStore(null);
11563 this.view.el.removeAllListeners();
11564 this.view.el.remove();
11565 this.view.purgeListeners();
11568 this.list.dom.innerHTML = '';
11572 this.store.un('beforeload', this.onBeforeLoad, this);
11573 this.store.un('load', this.onLoad, this);
11574 this.store.un('loadexception', this.onLoadException, this);
11576 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11580 fireKey : function(e){
11581 if(e.isNavKeyPress() && !this.list.isVisible()){
11582 this.fireEvent("specialkey", this, e);
11587 onResize: function(w, h){
11588 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11590 // if(typeof w != 'number'){
11591 // // we do not handle it!?!?
11594 // var tw = this.trigger.getWidth();
11595 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11596 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11598 // this.inputEl().setWidth( this.adjustWidth('input', x));
11600 // //this.trigger.setStyle('left', x+'px');
11602 // if(this.list && this.listWidth === undefined){
11603 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11604 // this.list.setWidth(lw);
11605 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11613 * Allow or prevent the user from directly editing the field text. If false is passed,
11614 * the user will only be able to select from the items defined in the dropdown list. This method
11615 * is the runtime equivalent of setting the 'editable' config option at config time.
11616 * @param {Boolean} value True to allow the user to directly edit the field text
11618 setEditable : function(value){
11619 if(value == this.editable){
11622 this.editable = value;
11624 this.inputEl().dom.setAttribute('readOnly', true);
11625 this.inputEl().on('mousedown', this.onTriggerClick, this);
11626 this.inputEl().addClass('x-combo-noedit');
11628 this.inputEl().dom.setAttribute('readOnly', false);
11629 this.inputEl().un('mousedown', this.onTriggerClick, this);
11630 this.inputEl().removeClass('x-combo-noedit');
11636 onBeforeLoad : function(combo,opts){
11637 if(!this.hasFocus){
11641 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11643 this.restrictHeight();
11644 this.selectedIndex = -1;
11648 onLoad : function(){
11650 this.hasQuery = false;
11652 if(!this.hasFocus){
11656 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11657 this.loading.hide();
11660 if(this.store.getCount() > 0){
11662 this.restrictHeight();
11663 if(this.lastQuery == this.allQuery){
11664 if(this.editable && !this.tickable){
11665 this.inputEl().dom.select();
11669 !this.selectByValue(this.value, true) &&
11672 !this.store.lastOptions ||
11673 typeof(this.store.lastOptions.add) == 'undefined' ||
11674 this.store.lastOptions.add != true
11677 this.select(0, true);
11680 if(this.autoFocus){
11683 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11684 this.taTask.delay(this.typeAheadDelay);
11688 this.onEmptyResults();
11694 onLoadException : function()
11696 this.hasQuery = false;
11698 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11699 this.loading.hide();
11702 if(this.tickable && this.editable){
11708 Roo.log(this.store.reader.jsonData);
11709 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11711 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11717 onTypeAhead : function(){
11718 if(this.store.getCount() > 0){
11719 var r = this.store.getAt(0);
11720 var newValue = r.data[this.displayField];
11721 var len = newValue.length;
11722 var selStart = this.getRawValue().length;
11724 if(selStart != len){
11725 this.setRawValue(newValue);
11726 this.selectText(selStart, newValue.length);
11732 onSelect : function(record, index){
11734 if(this.fireEvent('beforeselect', this, record, index) !== false){
11736 this.setFromData(index > -1 ? record.data : false);
11739 this.fireEvent('select', this, record, index);
11744 * Returns the currently selected field value or empty string if no value is set.
11745 * @return {String} value The selected value
11747 getValue : function(){
11750 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11753 if(this.valueField){
11754 return typeof this.value != 'undefined' ? this.value : '';
11756 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11761 * Clears any text/value currently set in the field
11763 clearValue : function(){
11764 if(this.hiddenField){
11765 this.hiddenField.dom.value = '';
11768 this.setRawValue('');
11769 this.lastSelectionText = '';
11770 this.lastData = false;
11775 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11776 * will be displayed in the field. If the value does not match the data value of an existing item,
11777 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11778 * Otherwise the field will be blank (although the value will still be set).
11779 * @param {String} value The value to match
11781 setValue : function(v){
11788 if(this.valueField){
11789 var r = this.findRecord(this.valueField, v);
11791 text = r.data[this.displayField];
11792 }else if(this.valueNotFoundText !== undefined){
11793 text = this.valueNotFoundText;
11796 this.lastSelectionText = text;
11797 if(this.hiddenField){
11798 this.hiddenField.dom.value = v;
11800 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11804 * @property {Object} the last set data for the element
11809 * Sets the value of the field based on a object which is related to the record format for the store.
11810 * @param {Object} value the value to set as. or false on reset?
11812 setFromData : function(o){
11819 var dv = ''; // display value
11820 var vv = ''; // value value..
11822 if (this.displayField) {
11823 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11825 // this is an error condition!!!
11826 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11829 if(this.valueField){
11830 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11833 if(this.hiddenField){
11834 this.hiddenField.dom.value = vv;
11836 this.lastSelectionText = dv;
11837 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11841 // no hidden field.. - we store the value in 'value', but still display
11842 // display field!!!!
11843 this.lastSelectionText = dv;
11844 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11850 reset : function(){
11851 // overridden so that last data is reset..
11858 this.setValue(this.originalValue);
11859 this.clearInvalid();
11860 this.lastData = false;
11862 this.view.clearSelections();
11866 findRecord : function(prop, value){
11868 if(this.store.getCount() > 0){
11869 this.store.each(function(r){
11870 if(r.data[prop] == value){
11880 getName: function()
11882 // returns hidden if it's set..
11883 if (!this.rendered) {return ''};
11884 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11888 onViewMove : function(e, t){
11889 this.inKeyMode = false;
11893 onViewOver : function(e, t){
11894 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11897 var item = this.view.findItemFromChild(t);
11900 var index = this.view.indexOf(item);
11901 this.select(index, false);
11906 onViewClick : function(view, doFocus, el, e)
11908 var index = this.view.getSelectedIndexes()[0];
11910 var r = this.store.getAt(index);
11914 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11921 Roo.each(this.tickItems, function(v,k){
11923 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11924 _this.tickItems.splice(k, 1);
11926 if(typeof(e) == 'undefined' && view == false){
11927 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11939 this.tickItems.push(r.data);
11941 if(typeof(e) == 'undefined' && view == false){
11942 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11949 this.onSelect(r, index);
11951 if(doFocus !== false && !this.blockFocus){
11952 this.inputEl().focus();
11957 restrictHeight : function(){
11958 //this.innerList.dom.style.height = '';
11959 //var inner = this.innerList.dom;
11960 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11961 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11962 //this.list.beginUpdate();
11963 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11964 this.list.alignTo(this.inputEl(), this.listAlign);
11965 this.list.alignTo(this.inputEl(), this.listAlign);
11966 //this.list.endUpdate();
11970 onEmptyResults : function(){
11972 if(this.tickable && this.editable){
11973 this.restrictHeight();
11981 * Returns true if the dropdown list is expanded, else false.
11983 isExpanded : function(){
11984 return this.list.isVisible();
11988 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11989 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11990 * @param {String} value The data value of the item to select
11991 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11992 * selected item if it is not currently in view (defaults to true)
11993 * @return {Boolean} True if the value matched an item in the list, else false
11995 selectByValue : function(v, scrollIntoView){
11996 if(v !== undefined && v !== null){
11997 var r = this.findRecord(this.valueField || this.displayField, v);
11999 this.select(this.store.indexOf(r), scrollIntoView);
12007 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12008 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12009 * @param {Number} index The zero-based index of the list item to select
12010 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12011 * selected item if it is not currently in view (defaults to true)
12013 select : function(index, scrollIntoView){
12014 this.selectedIndex = index;
12015 this.view.select(index);
12016 if(scrollIntoView !== false){
12017 var el = this.view.getNode(index);
12019 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12022 this.list.scrollChildIntoView(el, false);
12028 selectNext : function(){
12029 var ct = this.store.getCount();
12031 if(this.selectedIndex == -1){
12033 }else if(this.selectedIndex < ct-1){
12034 this.select(this.selectedIndex+1);
12040 selectPrev : function(){
12041 var ct = this.store.getCount();
12043 if(this.selectedIndex == -1){
12045 }else if(this.selectedIndex != 0){
12046 this.select(this.selectedIndex-1);
12052 onKeyUp : function(e){
12053 if(this.editable !== false && !e.isSpecialKey()){
12054 this.lastKey = e.getKey();
12055 this.dqTask.delay(this.queryDelay);
12060 validateBlur : function(){
12061 return !this.list || !this.list.isVisible();
12065 initQuery : function(){
12067 var v = this.getRawValue();
12069 if(this.tickable && this.editable){
12070 v = this.tickableInputEl().getValue();
12077 doForce : function(){
12078 if(this.inputEl().dom.value.length > 0){
12079 this.inputEl().dom.value =
12080 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12086 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12087 * query allowing the query action to be canceled if needed.
12088 * @param {String} query The SQL query to execute
12089 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12090 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12091 * saved in the current store (defaults to false)
12093 doQuery : function(q, forceAll){
12095 if(q === undefined || q === null){
12100 forceAll: forceAll,
12104 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12109 forceAll = qe.forceAll;
12110 if(forceAll === true || (q.length >= this.minChars)){
12112 this.hasQuery = true;
12114 if(this.lastQuery != q || this.alwaysQuery){
12115 this.lastQuery = q;
12116 if(this.mode == 'local'){
12117 this.selectedIndex = -1;
12119 this.store.clearFilter();
12122 if(this.specialFilter){
12123 this.fireEvent('specialfilter', this);
12128 this.store.filter(this.displayField, q);
12131 this.store.fireEvent("datachanged", this.store);
12138 this.store.baseParams[this.queryParam] = q;
12140 var options = {params : this.getParams(q)};
12143 options.add = true;
12144 options.params.start = this.page * this.pageSize;
12147 this.store.load(options);
12150 * this code will make the page width larger, at the beginning, the list not align correctly,
12151 * we should expand the list on onLoad
12152 * so command out it
12157 this.selectedIndex = -1;
12162 this.loadNext = false;
12166 getParams : function(q){
12168 //p[this.queryParam] = q;
12172 p.limit = this.pageSize;
12178 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12180 collapse : function(){
12181 if(!this.isExpanded()){
12188 this.hasFocus = false;
12190 this.cancelBtn.hide();
12191 this.trigger.show();
12194 this.tickableInputEl().dom.value = '';
12195 this.tickableInputEl().blur();
12200 Roo.get(document).un('mousedown', this.collapseIf, this);
12201 Roo.get(document).un('mousewheel', this.collapseIf, this);
12202 if (!this.editable) {
12203 Roo.get(document).un('keydown', this.listKeyPress, this);
12205 this.fireEvent('collapse', this);
12209 collapseIf : function(e){
12210 var in_combo = e.within(this.el);
12211 var in_list = e.within(this.list);
12212 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12214 if (in_combo || in_list || is_list) {
12215 //e.stopPropagation();
12220 this.onTickableFooterButtonClick(e, false, false);
12228 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12230 expand : function(){
12232 if(this.isExpanded() || !this.hasFocus){
12236 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12237 this.list.setWidth(lw);
12244 this.restrictHeight();
12248 this.tickItems = Roo.apply([], this.item);
12251 this.cancelBtn.show();
12252 this.trigger.hide();
12255 this.tickableInputEl().focus();
12260 Roo.get(document).on('mousedown', this.collapseIf, this);
12261 Roo.get(document).on('mousewheel', this.collapseIf, this);
12262 if (!this.editable) {
12263 Roo.get(document).on('keydown', this.listKeyPress, this);
12266 this.fireEvent('expand', this);
12270 // Implements the default empty TriggerField.onTriggerClick function
12271 onTriggerClick : function(e)
12273 Roo.log('trigger click');
12275 if(this.disabled || !this.triggerList){
12280 this.loadNext = false;
12282 if(this.isExpanded()){
12284 if (!this.blockFocus) {
12285 this.inputEl().focus();
12289 this.hasFocus = true;
12290 if(this.triggerAction == 'all') {
12291 this.doQuery(this.allQuery, true);
12293 this.doQuery(this.getRawValue());
12295 if (!this.blockFocus) {
12296 this.inputEl().focus();
12301 onTickableTriggerClick : function(e)
12308 this.loadNext = false;
12309 this.hasFocus = true;
12311 if(this.triggerAction == 'all') {
12312 this.doQuery(this.allQuery, true);
12314 this.doQuery(this.getRawValue());
12318 onSearchFieldClick : function(e)
12320 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12321 this.onTickableFooterButtonClick(e, false, false);
12325 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12330 this.loadNext = false;
12331 this.hasFocus = true;
12333 if(this.triggerAction == 'all') {
12334 this.doQuery(this.allQuery, true);
12336 this.doQuery(this.getRawValue());
12340 listKeyPress : function(e)
12342 //Roo.log('listkeypress');
12343 // scroll to first matching element based on key pres..
12344 if (e.isSpecialKey()) {
12347 var k = String.fromCharCode(e.getKey()).toUpperCase();
12350 var csel = this.view.getSelectedNodes();
12351 var cselitem = false;
12353 var ix = this.view.indexOf(csel[0]);
12354 cselitem = this.store.getAt(ix);
12355 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12361 this.store.each(function(v) {
12363 // start at existing selection.
12364 if (cselitem.id == v.id) {
12370 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12371 match = this.store.indexOf(v);
12377 if (match === false) {
12378 return true; // no more action?
12381 this.view.select(match);
12382 var sn = Roo.get(this.view.getSelectedNodes()[0])
12383 sn.scrollIntoView(sn.dom.parentNode, false);
12386 onViewScroll : function(e, t){
12388 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
12392 this.hasQuery = true;
12394 this.loading = this.list.select('.loading', true).first();
12396 if(this.loading === null){
12397 this.list.createChild({
12399 cls: 'loading select2-more-results select2-active',
12400 html: 'Loading more results...'
12403 this.loading = this.list.select('.loading', true).first();
12405 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12407 this.loading.hide();
12410 this.loading.show();
12415 this.loadNext = true;
12417 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12422 addItem : function(o)
12424 var dv = ''; // display value
12426 if (this.displayField) {
12427 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12429 // this is an error condition!!!
12430 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12437 var choice = this.choices.createChild({
12439 cls: 'select2-search-choice',
12448 cls: 'select2-search-choice-close',
12453 }, this.searchField);
12455 var close = choice.select('a.select2-search-choice-close', true).first()
12457 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12465 this.inputEl().dom.value = '';
12470 onRemoveItem : function(e, _self, o)
12472 e.preventDefault();
12474 this.lastItem = Roo.apply([], this.item);
12476 var index = this.item.indexOf(o.data) * 1;
12479 Roo.log('not this item?!');
12483 this.item.splice(index, 1);
12488 this.fireEvent('remove', this, e);
12494 syncValue : function()
12496 if(!this.item.length){
12503 Roo.each(this.item, function(i){
12504 if(_this.valueField){
12505 value.push(i[_this.valueField]);
12512 this.value = value.join(',');
12514 if(this.hiddenField){
12515 this.hiddenField.dom.value = this.value;
12518 this.store.fireEvent("datachanged", this.store);
12521 clearItem : function()
12523 if(!this.multiple){
12529 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12538 inputEl: function ()
12541 return this.searchField;
12543 return this.el.select('input.form-control',true).first();
12547 onTickableFooterButtonClick : function(e, btn, el)
12549 e.preventDefault();
12551 this.lastItem = Roo.apply([], this.item);
12553 if(btn && btn.name == 'cancel'){
12554 this.tickItems = Roo.apply([], this.item);
12563 Roo.each(this.tickItems, function(o){
12571 validate : function()
12573 var v = this.getRawValue();
12576 v = this.getValue();
12579 if(this.disabled || this.allowBlank || v.length){
12584 this.markInvalid();
12588 tickableInputEl : function()
12590 if(!this.tickable || !this.editable){
12591 return this.inputEl();
12594 return this.inputEl().select('.select2-search-field-input', true).first();
12600 * @cfg {Boolean} grow
12604 * @cfg {Number} growMin
12608 * @cfg {Number} growMax
12618 * Ext JS Library 1.1.1
12619 * Copyright(c) 2006-2007, Ext JS, LLC.
12621 * Originally Released Under LGPL - original licence link has changed is not relivant.
12624 * <script type="text/javascript">
12629 * @extends Roo.util.Observable
12630 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12631 * This class also supports single and multi selection modes. <br>
12632 * Create a data model bound view:
12634 var store = new Roo.data.Store(...);
12636 var view = new Roo.View({
12638 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12640 singleSelect: true,
12641 selectedClass: "ydataview-selected",
12645 // listen for node click?
12646 view.on("click", function(vw, index, node, e){
12647 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12651 dataModel.load("foobar.xml");
12653 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12655 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12656 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12658 * Note: old style constructor is still suported (container, template, config)
12661 * Create a new View
12662 * @param {Object} config The config object
12665 Roo.View = function(config, depreciated_tpl, depreciated_config){
12667 this.parent = false;
12669 if (typeof(depreciated_tpl) == 'undefined') {
12670 // new way.. - universal constructor.
12671 Roo.apply(this, config);
12672 this.el = Roo.get(this.el);
12675 this.el = Roo.get(config);
12676 this.tpl = depreciated_tpl;
12677 Roo.apply(this, depreciated_config);
12679 this.wrapEl = this.el.wrap().wrap();
12680 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12683 if(typeof(this.tpl) == "string"){
12684 this.tpl = new Roo.Template(this.tpl);
12686 // support xtype ctors..
12687 this.tpl = new Roo.factory(this.tpl, Roo);
12691 this.tpl.compile();
12696 * @event beforeclick
12697 * Fires before a click is processed. Returns false to cancel the default action.
12698 * @param {Roo.View} this
12699 * @param {Number} index The index of the target node
12700 * @param {HTMLElement} node The target node
12701 * @param {Roo.EventObject} e The raw event object
12703 "beforeclick" : true,
12706 * Fires when a template node is clicked.
12707 * @param {Roo.View} this
12708 * @param {Number} index The index of the target node
12709 * @param {HTMLElement} node The target node
12710 * @param {Roo.EventObject} e The raw event object
12715 * Fires when a template node is double clicked.
12716 * @param {Roo.View} this
12717 * @param {Number} index The index of the target node
12718 * @param {HTMLElement} node The target node
12719 * @param {Roo.EventObject} e The raw event object
12723 * @event contextmenu
12724 * Fires when a template node is right clicked.
12725 * @param {Roo.View} this
12726 * @param {Number} index The index of the target node
12727 * @param {HTMLElement} node The target node
12728 * @param {Roo.EventObject} e The raw event object
12730 "contextmenu" : true,
12732 * @event selectionchange
12733 * Fires when the selected nodes change.
12734 * @param {Roo.View} this
12735 * @param {Array} selections Array of the selected nodes
12737 "selectionchange" : true,
12740 * @event beforeselect
12741 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12742 * @param {Roo.View} this
12743 * @param {HTMLElement} node The node to be selected
12744 * @param {Array} selections Array of currently selected nodes
12746 "beforeselect" : true,
12748 * @event preparedata
12749 * Fires on every row to render, to allow you to change the data.
12750 * @param {Roo.View} this
12751 * @param {Object} data to be rendered (change this)
12753 "preparedata" : true
12761 "click": this.onClick,
12762 "dblclick": this.onDblClick,
12763 "contextmenu": this.onContextMenu,
12767 this.selections = [];
12769 this.cmp = new Roo.CompositeElementLite([]);
12771 this.store = Roo.factory(this.store, Roo.data);
12772 this.setStore(this.store, true);
12775 if ( this.footer && this.footer.xtype) {
12777 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12779 this.footer.dataSource = this.store
12780 this.footer.container = fctr;
12781 this.footer = Roo.factory(this.footer, Roo);
12782 fctr.insertFirst(this.el);
12784 // this is a bit insane - as the paging toolbar seems to detach the el..
12785 // dom.parentNode.parentNode.parentNode
12786 // they get detached?
12790 Roo.View.superclass.constructor.call(this);
12795 Roo.extend(Roo.View, Roo.util.Observable, {
12798 * @cfg {Roo.data.Store} store Data store to load data from.
12803 * @cfg {String|Roo.Element} el The container element.
12808 * @cfg {String|Roo.Template} tpl The template used by this View
12812 * @cfg {String} dataName the named area of the template to use as the data area
12813 * Works with domtemplates roo-name="name"
12817 * @cfg {String} selectedClass The css class to add to selected nodes
12819 selectedClass : "x-view-selected",
12821 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12826 * @cfg {String} text to display on mask (default Loading)
12830 * @cfg {Boolean} multiSelect Allow multiple selection
12832 multiSelect : false,
12834 * @cfg {Boolean} singleSelect Allow single selection
12836 singleSelect: false,
12839 * @cfg {Boolean} toggleSelect - selecting
12841 toggleSelect : false,
12844 * @cfg {Boolean} tickable - selecting
12849 * Returns the element this view is bound to.
12850 * @return {Roo.Element}
12852 getEl : function(){
12853 return this.wrapEl;
12859 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12861 refresh : function(){
12862 //Roo.log('refresh');
12865 // if we are using something like 'domtemplate', then
12866 // the what gets used is:
12867 // t.applySubtemplate(NAME, data, wrapping data..)
12868 // the outer template then get' applied with
12869 // the store 'extra data'
12870 // and the body get's added to the
12871 // roo-name="data" node?
12872 // <span class='roo-tpl-{name}'></span> ?????
12876 this.clearSelections();
12877 this.el.update("");
12879 var records = this.store.getRange();
12880 if(records.length < 1) {
12882 // is this valid?? = should it render a template??
12884 this.el.update(this.emptyText);
12888 if (this.dataName) {
12889 this.el.update(t.apply(this.store.meta)); //????
12890 el = this.el.child('.roo-tpl-' + this.dataName);
12893 for(var i = 0, len = records.length; i < len; i++){
12894 var data = this.prepareData(records[i].data, i, records[i]);
12895 this.fireEvent("preparedata", this, data, i, records[i]);
12897 var d = Roo.apply({}, data);
12900 Roo.apply(d, {'roo-id' : Roo.id()});
12904 Roo.each(this.parent.item, function(item){
12905 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12908 Roo.apply(d, {'roo-data-checked' : 'checked'});
12912 html[html.length] = Roo.util.Format.trim(
12914 t.applySubtemplate(this.dataName, d, this.store.meta) :
12921 el.update(html.join(""));
12922 this.nodes = el.dom.childNodes;
12923 this.updateIndexes(0);
12928 * Function to override to reformat the data that is sent to
12929 * the template for each node.
12930 * DEPRICATED - use the preparedata event handler.
12931 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12932 * a JSON object for an UpdateManager bound view).
12934 prepareData : function(data, index, record)
12936 this.fireEvent("preparedata", this, data, index, record);
12940 onUpdate : function(ds, record){
12941 // Roo.log('on update');
12942 this.clearSelections();
12943 var index = this.store.indexOf(record);
12944 var n = this.nodes[index];
12945 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12946 n.parentNode.removeChild(n);
12947 this.updateIndexes(index, index);
12953 onAdd : function(ds, records, index)
12955 //Roo.log(['on Add', ds, records, index] );
12956 this.clearSelections();
12957 if(this.nodes.length == 0){
12961 var n = this.nodes[index];
12962 for(var i = 0, len = records.length; i < len; i++){
12963 var d = this.prepareData(records[i].data, i, records[i]);
12965 this.tpl.insertBefore(n, d);
12968 this.tpl.append(this.el, d);
12971 this.updateIndexes(index);
12974 onRemove : function(ds, record, index){
12975 // Roo.log('onRemove');
12976 this.clearSelections();
12977 var el = this.dataName ?
12978 this.el.child('.roo-tpl-' + this.dataName) :
12981 el.dom.removeChild(this.nodes[index]);
12982 this.updateIndexes(index);
12986 * Refresh an individual node.
12987 * @param {Number} index
12989 refreshNode : function(index){
12990 this.onUpdate(this.store, this.store.getAt(index));
12993 updateIndexes : function(startIndex, endIndex){
12994 var ns = this.nodes;
12995 startIndex = startIndex || 0;
12996 endIndex = endIndex || ns.length - 1;
12997 for(var i = startIndex; i <= endIndex; i++){
12998 ns[i].nodeIndex = i;
13003 * Changes the data store this view uses and refresh the view.
13004 * @param {Store} store
13006 setStore : function(store, initial){
13007 if(!initial && this.store){
13008 this.store.un("datachanged", this.refresh);
13009 this.store.un("add", this.onAdd);
13010 this.store.un("remove", this.onRemove);
13011 this.store.un("update", this.onUpdate);
13012 this.store.un("clear", this.refresh);
13013 this.store.un("beforeload", this.onBeforeLoad);
13014 this.store.un("load", this.onLoad);
13015 this.store.un("loadexception", this.onLoad);
13019 store.on("datachanged", this.refresh, this);
13020 store.on("add", this.onAdd, this);
13021 store.on("remove", this.onRemove, this);
13022 store.on("update", this.onUpdate, this);
13023 store.on("clear", this.refresh, this);
13024 store.on("beforeload", this.onBeforeLoad, this);
13025 store.on("load", this.onLoad, this);
13026 store.on("loadexception", this.onLoad, this);
13034 * onbeforeLoad - masks the loading area.
13037 onBeforeLoad : function(store,opts)
13039 //Roo.log('onBeforeLoad');
13041 this.el.update("");
13043 this.el.mask(this.mask ? this.mask : "Loading" );
13045 onLoad : function ()
13052 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13053 * @param {HTMLElement} node
13054 * @return {HTMLElement} The template node
13056 findItemFromChild : function(node){
13057 var el = this.dataName ?
13058 this.el.child('.roo-tpl-' + this.dataName,true) :
13061 if(!node || node.parentNode == el){
13064 var p = node.parentNode;
13065 while(p && p != el){
13066 if(p.parentNode == el){
13075 onClick : function(e){
13076 var item = this.findItemFromChild(e.getTarget());
13078 var index = this.indexOf(item);
13079 if(this.onItemClick(item, index, e) !== false){
13080 this.fireEvent("click", this, index, item, e);
13083 this.clearSelections();
13088 onContextMenu : function(e){
13089 var item = this.findItemFromChild(e.getTarget());
13091 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13096 onDblClick : function(e){
13097 var item = this.findItemFromChild(e.getTarget());
13099 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13103 onItemClick : function(item, index, e)
13105 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13108 if (this.toggleSelect) {
13109 var m = this.isSelected(item) ? 'unselect' : 'select';
13112 _t[m](item, true, false);
13115 if(this.multiSelect || this.singleSelect){
13116 if(this.multiSelect && e.shiftKey && this.lastSelection){
13117 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13119 this.select(item, this.multiSelect && e.ctrlKey);
13120 this.lastSelection = item;
13123 if(!this.tickable){
13124 e.preventDefault();
13132 * Get the number of selected nodes.
13135 getSelectionCount : function(){
13136 return this.selections.length;
13140 * Get the currently selected nodes.
13141 * @return {Array} An array of HTMLElements
13143 getSelectedNodes : function(){
13144 return this.selections;
13148 * Get the indexes of the selected nodes.
13151 getSelectedIndexes : function(){
13152 var indexes = [], s = this.selections;
13153 for(var i = 0, len = s.length; i < len; i++){
13154 indexes.push(s[i].nodeIndex);
13160 * Clear all selections
13161 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13163 clearSelections : function(suppressEvent){
13164 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13165 this.cmp.elements = this.selections;
13166 this.cmp.removeClass(this.selectedClass);
13167 this.selections = [];
13168 if(!suppressEvent){
13169 this.fireEvent("selectionchange", this, this.selections);
13175 * Returns true if the passed node is selected
13176 * @param {HTMLElement/Number} node The node or node index
13177 * @return {Boolean}
13179 isSelected : function(node){
13180 var s = this.selections;
13184 node = this.getNode(node);
13185 return s.indexOf(node) !== -1;
13190 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
13191 * @param {Boolean} keepExisting (optional) true to keep existing selections
13192 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13194 select : function(nodeInfo, keepExisting, suppressEvent){
13195 if(nodeInfo instanceof Array){
13197 this.clearSelections(true);
13199 for(var i = 0, len = nodeInfo.length; i < len; i++){
13200 this.select(nodeInfo[i], true, true);
13204 var node = this.getNode(nodeInfo);
13205 if(!node || this.isSelected(node)){
13206 return; // already selected.
13209 this.clearSelections(true);
13212 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13213 Roo.fly(node).addClass(this.selectedClass);
13214 this.selections.push(node);
13215 if(!suppressEvent){
13216 this.fireEvent("selectionchange", this, this.selections);
13224 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
13225 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13226 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13228 unselect : function(nodeInfo, keepExisting, suppressEvent)
13230 if(nodeInfo instanceof Array){
13231 Roo.each(this.selections, function(s) {
13232 this.unselect(s, nodeInfo);
13236 var node = this.getNode(nodeInfo);
13237 if(!node || !this.isSelected(node)){
13238 //Roo.log("not selected");
13239 return; // not selected.
13243 Roo.each(this.selections, function(s) {
13245 Roo.fly(node).removeClass(this.selectedClass);
13252 this.selections= ns;
13253 this.fireEvent("selectionchange", this, this.selections);
13257 * Gets a template node.
13258 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13259 * @return {HTMLElement} The node or null if it wasn't found
13261 getNode : function(nodeInfo){
13262 if(typeof nodeInfo == "string"){
13263 return document.getElementById(nodeInfo);
13264 }else if(typeof nodeInfo == "number"){
13265 return this.nodes[nodeInfo];
13271 * Gets a range template nodes.
13272 * @param {Number} startIndex
13273 * @param {Number} endIndex
13274 * @return {Array} An array of nodes
13276 getNodes : function(start, end){
13277 var ns = this.nodes;
13278 start = start || 0;
13279 end = typeof end == "undefined" ? ns.length - 1 : end;
13282 for(var i = start; i <= end; i++){
13286 for(var i = start; i >= end; i--){
13294 * Finds the index of the passed node
13295 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13296 * @return {Number} The index of the node or -1
13298 indexOf : function(node){
13299 node = this.getNode(node);
13300 if(typeof node.nodeIndex == "number"){
13301 return node.nodeIndex;
13303 var ns = this.nodes;
13304 for(var i = 0, len = ns.length; i < len; i++){
13315 * based on jquery fullcalendar
13319 Roo.bootstrap = Roo.bootstrap || {};
13321 * @class Roo.bootstrap.Calendar
13322 * @extends Roo.bootstrap.Component
13323 * Bootstrap Calendar class
13324 * @cfg {Boolean} loadMask (true|false) default false
13325 * @cfg {Object} header generate the user specific header of the calendar, default false
13328 * Create a new Container
13329 * @param {Object} config The config object
13334 Roo.bootstrap.Calendar = function(config){
13335 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13339 * Fires when a date is selected
13340 * @param {DatePicker} this
13341 * @param {Date} date The selected date
13345 * @event monthchange
13346 * Fires when the displayed month changes
13347 * @param {DatePicker} this
13348 * @param {Date} date The selected month
13350 'monthchange': true,
13352 * @event evententer
13353 * Fires when mouse over an event
13354 * @param {Calendar} this
13355 * @param {event} Event
13357 'evententer': true,
13359 * @event eventleave
13360 * Fires when the mouse leaves an
13361 * @param {Calendar} this
13364 'eventleave': true,
13366 * @event eventclick
13367 * Fires when the mouse click an
13368 * @param {Calendar} this
13377 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13380 * @cfg {Number} startDay
13381 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13389 getAutoCreate : function(){
13392 var fc_button = function(name, corner, style, content ) {
13393 return Roo.apply({},{
13395 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13397 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13400 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13411 style : 'width:100%',
13418 cls : 'fc-header-left',
13420 fc_button('prev', 'left', 'arrow', '‹' ),
13421 fc_button('next', 'right', 'arrow', '›' ),
13422 { tag: 'span', cls: 'fc-header-space' },
13423 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13431 cls : 'fc-header-center',
13435 cls: 'fc-header-title',
13438 html : 'month / year'
13446 cls : 'fc-header-right',
13448 /* fc_button('month', 'left', '', 'month' ),
13449 fc_button('week', '', '', 'week' ),
13450 fc_button('day', 'right', '', 'day' )
13462 header = this.header;
13465 var cal_heads = function() {
13467 // fixme - handle this.
13469 for (var i =0; i < Date.dayNames.length; i++) {
13470 var d = Date.dayNames[i];
13473 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13474 html : d.substring(0,3)
13478 ret[0].cls += ' fc-first';
13479 ret[6].cls += ' fc-last';
13482 var cal_cell = function(n) {
13485 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13490 cls: 'fc-day-number',
13494 cls: 'fc-day-content',
13498 style: 'position: relative;' // height: 17px;
13510 var cal_rows = function() {
13513 for (var r = 0; r < 6; r++) {
13520 for (var i =0; i < Date.dayNames.length; i++) {
13521 var d = Date.dayNames[i];
13522 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13525 row.cn[0].cls+=' fc-first';
13526 row.cn[0].cn[0].style = 'min-height:90px';
13527 row.cn[6].cls+=' fc-last';
13531 ret[0].cls += ' fc-first';
13532 ret[4].cls += ' fc-prev-last';
13533 ret[5].cls += ' fc-last';
13540 cls: 'fc-border-separate',
13541 style : 'width:100%',
13549 cls : 'fc-first fc-last',
13567 cls : 'fc-content',
13568 style : "position: relative;",
13571 cls : 'fc-view fc-view-month fc-grid',
13572 style : 'position: relative',
13573 unselectable : 'on',
13576 cls : 'fc-event-container',
13577 style : 'position:absolute;z-index:8;top:0;left:0;'
13595 initEvents : function()
13598 throw "can not find store for calendar";
13604 style: "text-align:center",
13608 style: "background-color:white;width:50%;margin:250 auto",
13612 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13623 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13625 var size = this.el.select('.fc-content', true).first().getSize();
13626 this.maskEl.setSize(size.width, size.height);
13627 this.maskEl.enableDisplayMode("block");
13628 if(!this.loadMask){
13629 this.maskEl.hide();
13632 this.store = Roo.factory(this.store, Roo.data);
13633 this.store.on('load', this.onLoad, this);
13634 this.store.on('beforeload', this.onBeforeLoad, this);
13638 this.cells = this.el.select('.fc-day',true);
13639 //Roo.log(this.cells);
13640 this.textNodes = this.el.query('.fc-day-number');
13641 this.cells.addClassOnOver('fc-state-hover');
13643 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13644 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13645 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13646 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13648 this.on('monthchange', this.onMonthChange, this);
13650 this.update(new Date().clearTime());
13653 resize : function() {
13654 var sz = this.el.getSize();
13656 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13657 this.el.select('.fc-day-content div',true).setHeight(34);
13662 showPrevMonth : function(e){
13663 this.update(this.activeDate.add("mo", -1));
13665 showToday : function(e){
13666 this.update(new Date().clearTime());
13669 showNextMonth : function(e){
13670 this.update(this.activeDate.add("mo", 1));
13674 showPrevYear : function(){
13675 this.update(this.activeDate.add("y", -1));
13679 showNextYear : function(){
13680 this.update(this.activeDate.add("y", 1));
13685 update : function(date)
13687 var vd = this.activeDate;
13688 this.activeDate = date;
13689 // if(vd && this.el){
13690 // var t = date.getTime();
13691 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13692 // Roo.log('using add remove');
13694 // this.fireEvent('monthchange', this, date);
13696 // this.cells.removeClass("fc-state-highlight");
13697 // this.cells.each(function(c){
13698 // if(c.dateValue == t){
13699 // c.addClass("fc-state-highlight");
13700 // setTimeout(function(){
13701 // try{c.dom.firstChild.focus();}catch(e){}
13711 var days = date.getDaysInMonth();
13713 var firstOfMonth = date.getFirstDateOfMonth();
13714 var startingPos = firstOfMonth.getDay()-this.startDay;
13716 if(startingPos < this.startDay){
13720 var pm = date.add(Date.MONTH, -1);
13721 var prevStart = pm.getDaysInMonth()-startingPos;
13723 this.cells = this.el.select('.fc-day',true);
13724 this.textNodes = this.el.query('.fc-day-number');
13725 this.cells.addClassOnOver('fc-state-hover');
13727 var cells = this.cells.elements;
13728 var textEls = this.textNodes;
13730 Roo.each(cells, function(cell){
13731 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13734 days += startingPos;
13736 // convert everything to numbers so it's fast
13737 var day = 86400000;
13738 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13741 //Roo.log(prevStart);
13743 var today = new Date().clearTime().getTime();
13744 var sel = date.clearTime().getTime();
13745 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13746 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13747 var ddMatch = this.disabledDatesRE;
13748 var ddText = this.disabledDatesText;
13749 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13750 var ddaysText = this.disabledDaysText;
13751 var format = this.format;
13753 var setCellClass = function(cal, cell){
13757 //Roo.log('set Cell Class');
13759 var t = d.getTime();
13763 cell.dateValue = t;
13765 cell.className += " fc-today";
13766 cell.className += " fc-state-highlight";
13767 cell.title = cal.todayText;
13770 // disable highlight in other month..
13771 //cell.className += " fc-state-highlight";
13776 cell.className = " fc-state-disabled";
13777 cell.title = cal.minText;
13781 cell.className = " fc-state-disabled";
13782 cell.title = cal.maxText;
13786 if(ddays.indexOf(d.getDay()) != -1){
13787 cell.title = ddaysText;
13788 cell.className = " fc-state-disabled";
13791 if(ddMatch && format){
13792 var fvalue = d.dateFormat(format);
13793 if(ddMatch.test(fvalue)){
13794 cell.title = ddText.replace("%0", fvalue);
13795 cell.className = " fc-state-disabled";
13799 if (!cell.initialClassName) {
13800 cell.initialClassName = cell.dom.className;
13803 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13808 for(; i < startingPos; i++) {
13809 textEls[i].innerHTML = (++prevStart);
13810 d.setDate(d.getDate()+1);
13812 cells[i].className = "fc-past fc-other-month";
13813 setCellClass(this, cells[i]);
13818 for(; i < days; i++){
13819 intDay = i - startingPos + 1;
13820 textEls[i].innerHTML = (intDay);
13821 d.setDate(d.getDate()+1);
13823 cells[i].className = ''; // "x-date-active";
13824 setCellClass(this, cells[i]);
13828 for(; i < 42; i++) {
13829 textEls[i].innerHTML = (++extraDays);
13830 d.setDate(d.getDate()+1);
13832 cells[i].className = "fc-future fc-other-month";
13833 setCellClass(this, cells[i]);
13836 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13838 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13840 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13841 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13843 if(totalRows != 6){
13844 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13845 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13848 this.fireEvent('monthchange', this, date);
13852 if(!this.internalRender){
13853 var main = this.el.dom.firstChild;
13854 var w = main.offsetWidth;
13855 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13856 Roo.fly(main).setWidth(w);
13857 this.internalRender = true;
13858 // opera does not respect the auto grow header center column
13859 // then, after it gets a width opera refuses to recalculate
13860 // without a second pass
13861 if(Roo.isOpera && !this.secondPass){
13862 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13863 this.secondPass = true;
13864 this.update.defer(10, this, [date]);
13871 findCell : function(dt) {
13872 dt = dt.clearTime().getTime();
13874 this.cells.each(function(c){
13875 //Roo.log("check " +c.dateValue + '?=' + dt);
13876 if(c.dateValue == dt){
13886 findCells : function(ev) {
13887 var s = ev.start.clone().clearTime().getTime();
13889 var e= ev.end.clone().clearTime().getTime();
13892 this.cells.each(function(c){
13893 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13895 if(c.dateValue > e){
13898 if(c.dateValue < s){
13907 // findBestRow: function(cells)
13911 // for (var i =0 ; i < cells.length;i++) {
13912 // ret = Math.max(cells[i].rows || 0,ret);
13919 addItem : function(ev)
13921 // look for vertical location slot in
13922 var cells = this.findCells(ev);
13924 // ev.row = this.findBestRow(cells);
13926 // work out the location.
13930 for(var i =0; i < cells.length; i++) {
13932 cells[i].row = cells[0].row;
13935 cells[i].row = cells[i].row + 1;
13945 if (crow.start.getY() == cells[i].getY()) {
13947 crow.end = cells[i];
13964 cells[0].events.push(ev);
13966 this.calevents.push(ev);
13969 clearEvents: function() {
13971 if(!this.calevents){
13975 Roo.each(this.cells.elements, function(c){
13981 Roo.each(this.calevents, function(e) {
13982 Roo.each(e.els, function(el) {
13983 el.un('mouseenter' ,this.onEventEnter, this);
13984 el.un('mouseleave' ,this.onEventLeave, this);
13989 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13995 renderEvents: function()
13999 this.cells.each(function(c) {
14008 if(c.row != c.events.length){
14009 r = 4 - (4 - (c.row - c.events.length));
14012 c.events = ev.slice(0, r);
14013 c.more = ev.slice(r);
14015 if(c.more.length && c.more.length == 1){
14016 c.events.push(c.more.pop());
14019 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14023 this.cells.each(function(c) {
14025 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14028 for (var e = 0; e < c.events.length; e++){
14029 var ev = c.events[e];
14030 var rows = ev.rows;
14032 for(var i = 0; i < rows.length; i++) {
14034 // how many rows should it span..
14037 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14038 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14040 unselectable : "on",
14043 cls: 'fc-event-inner',
14047 // cls: 'fc-event-time',
14048 // html : cells.length > 1 ? '' : ev.time
14052 cls: 'fc-event-title',
14053 html : String.format('{0}', ev.title)
14060 cls: 'ui-resizable-handle ui-resizable-e',
14061 html : '  '
14068 cfg.cls += ' fc-event-start';
14070 if ((i+1) == rows.length) {
14071 cfg.cls += ' fc-event-end';
14074 var ctr = _this.el.select('.fc-event-container',true).first();
14075 var cg = ctr.createChild(cfg);
14077 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14078 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14080 var r = (c.more.length) ? 1 : 0;
14081 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14082 cg.setWidth(ebox.right - sbox.x -2);
14084 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14085 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14086 cg.on('click', _this.onEventClick, _this, ev);
14097 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14098 style : 'position: absolute',
14099 unselectable : "on",
14102 cls: 'fc-event-inner',
14106 cls: 'fc-event-title',
14114 cls: 'ui-resizable-handle ui-resizable-e',
14115 html : '  '
14121 var ctr = _this.el.select('.fc-event-container',true).first();
14122 var cg = ctr.createChild(cfg);
14124 var sbox = c.select('.fc-day-content',true).first().getBox();
14125 var ebox = c.select('.fc-day-content',true).first().getBox();
14127 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14128 cg.setWidth(ebox.right - sbox.x -2);
14130 cg.on('click', _this.onMoreEventClick, _this, c.more);
14140 onEventEnter: function (e, el,event,d) {
14141 this.fireEvent('evententer', this, el, event);
14144 onEventLeave: function (e, el,event,d) {
14145 this.fireEvent('eventleave', this, el, event);
14148 onEventClick: function (e, el,event,d) {
14149 this.fireEvent('eventclick', this, el, event);
14152 onMonthChange: function () {
14156 onMoreEventClick: function(e, el, more)
14160 this.calpopover.placement = 'right';
14161 this.calpopover.setTitle('More');
14163 this.calpopover.setContent('');
14165 var ctr = this.calpopover.el.select('.popover-content', true).first();
14167 Roo.each(more, function(m){
14169 cls : 'fc-event-hori fc-event-draggable',
14172 var cg = ctr.createChild(cfg);
14174 cg.on('click', _this.onEventClick, _this, m);
14177 this.calpopover.show(el);
14182 onLoad: function ()
14184 this.calevents = [];
14187 if(this.store.getCount() > 0){
14188 this.store.data.each(function(d){
14191 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14192 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14193 time : d.data.start_time,
14194 title : d.data.title,
14195 description : d.data.description,
14196 venue : d.data.venue
14201 this.renderEvents();
14203 if(this.calevents.length && this.loadMask){
14204 this.maskEl.hide();
14208 onBeforeLoad: function()
14210 this.clearEvents();
14212 this.maskEl.show();
14226 * @class Roo.bootstrap.Popover
14227 * @extends Roo.bootstrap.Component
14228 * Bootstrap Popover class
14229 * @cfg {String} html contents of the popover (or false to use children..)
14230 * @cfg {String} title of popover (or false to hide)
14231 * @cfg {String} placement how it is placed
14232 * @cfg {String} trigger click || hover (or false to trigger manually)
14233 * @cfg {String} over what (parent or false to trigger manually.)
14234 * @cfg {Number} delay - delay before showing
14237 * Create a new Popover
14238 * @param {Object} config The config object
14241 Roo.bootstrap.Popover = function(config){
14242 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14245 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14247 title: 'Fill in a title',
14250 placement : 'right',
14251 trigger : 'hover', // hover
14257 can_build_overlaid : false,
14259 getChildContainer : function()
14261 return this.el.select('.popover-content',true).first();
14264 getAutoCreate : function(){
14265 Roo.log('make popover?');
14267 cls : 'popover roo-dynamic',
14268 style: 'display:block',
14274 cls : 'popover-inner',
14278 cls: 'popover-title',
14282 cls : 'popover-content',
14293 setTitle: function(str)
14295 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14297 setContent: function(str)
14299 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14301 // as it get's added to the bottom of the page.
14302 onRender : function(ct, position)
14304 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14306 var cfg = Roo.apply({}, this.getAutoCreate());
14310 cfg.cls += ' ' + this.cls;
14313 cfg.style = this.style;
14315 Roo.log("adding to ")
14316 this.el = Roo.get(document.body).createChild(cfg, position);
14322 initEvents : function()
14324 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14325 this.el.enableDisplayMode('block');
14327 if (this.over === false) {
14330 if (this.triggers === false) {
14333 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14334 var triggers = this.trigger ? this.trigger.split(' ') : [];
14335 Roo.each(triggers, function(trigger) {
14337 if (trigger == 'click') {
14338 on_el.on('click', this.toggle, this);
14339 } else if (trigger != 'manual') {
14340 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14341 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14343 on_el.on(eventIn ,this.enter, this);
14344 on_el.on(eventOut, this.leave, this);
14355 toggle : function () {
14356 this.hoverState == 'in' ? this.leave() : this.enter();
14359 enter : function () {
14362 clearTimeout(this.timeout);
14364 this.hoverState = 'in';
14366 if (!this.delay || !this.delay.show) {
14371 this.timeout = setTimeout(function () {
14372 if (_t.hoverState == 'in') {
14375 }, this.delay.show)
14377 leave : function() {
14378 clearTimeout(this.timeout);
14380 this.hoverState = 'out';
14382 if (!this.delay || !this.delay.hide) {
14387 this.timeout = setTimeout(function () {
14388 if (_t.hoverState == 'out') {
14391 }, this.delay.hide)
14394 show : function (on_el)
14397 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14400 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14401 if (this.html !== false) {
14402 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14404 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14405 if (!this.title.length) {
14406 this.el.select('.popover-title',true).hide();
14409 var placement = typeof this.placement == 'function' ?
14410 this.placement.call(this, this.el, on_el) :
14413 var autoToken = /\s?auto?\s?/i;
14414 var autoPlace = autoToken.test(placement);
14416 placement = placement.replace(autoToken, '') || 'top';
14420 //this.el.setXY([0,0]);
14422 this.el.dom.style.display='block';
14423 this.el.addClass(placement);
14425 //this.el.appendTo(on_el);
14427 var p = this.getPosition();
14428 var box = this.el.getBox();
14433 var align = Roo.bootstrap.Popover.alignment[placement];
14434 this.el.alignTo(on_el, align[0],align[1]);
14435 //var arrow = this.el.select('.arrow',true).first();
14436 //arrow.set(align[2],
14438 this.el.addClass('in');
14439 this.hoverState = null;
14441 if (this.el.hasClass('fade')) {
14448 this.el.setXY([0,0]);
14449 this.el.removeClass('in');
14456 Roo.bootstrap.Popover.alignment = {
14457 'left' : ['r-l', [-10,0], 'right'],
14458 'right' : ['l-r', [10,0], 'left'],
14459 'bottom' : ['t-b', [0,10], 'top'],
14460 'top' : [ 'b-t', [0,-10], 'bottom']
14471 * @class Roo.bootstrap.Progress
14472 * @extends Roo.bootstrap.Component
14473 * Bootstrap Progress class
14474 * @cfg {Boolean} striped striped of the progress bar
14475 * @cfg {Boolean} active animated of the progress bar
14479 * Create a new Progress
14480 * @param {Object} config The config object
14483 Roo.bootstrap.Progress = function(config){
14484 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14487 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14492 getAutoCreate : function(){
14500 cfg.cls += ' progress-striped';
14504 cfg.cls += ' active';
14523 * @class Roo.bootstrap.ProgressBar
14524 * @extends Roo.bootstrap.Component
14525 * Bootstrap ProgressBar class
14526 * @cfg {Number} aria_valuenow aria-value now
14527 * @cfg {Number} aria_valuemin aria-value min
14528 * @cfg {Number} aria_valuemax aria-value max
14529 * @cfg {String} label label for the progress bar
14530 * @cfg {String} panel (success | info | warning | danger )
14531 * @cfg {String} role role of the progress bar
14532 * @cfg {String} sr_only text
14536 * Create a new ProgressBar
14537 * @param {Object} config The config object
14540 Roo.bootstrap.ProgressBar = function(config){
14541 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14544 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14548 aria_valuemax : 100,
14554 getAutoCreate : function()
14559 cls: 'progress-bar',
14560 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14572 cfg.role = this.role;
14575 if(this.aria_valuenow){
14576 cfg['aria-valuenow'] = this.aria_valuenow;
14579 if(this.aria_valuemin){
14580 cfg['aria-valuemin'] = this.aria_valuemin;
14583 if(this.aria_valuemax){
14584 cfg['aria-valuemax'] = this.aria_valuemax;
14587 if(this.label && !this.sr_only){
14588 cfg.html = this.label;
14592 cfg.cls += ' progress-bar-' + this.panel;
14598 update : function(aria_valuenow)
14600 this.aria_valuenow = aria_valuenow;
14602 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14617 * @class Roo.bootstrap.TabGroup
14618 * @extends Roo.bootstrap.Column
14619 * Bootstrap Column class
14620 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14621 * @cfg {Boolean} carousel true to make the group behave like a carousel
14622 * @cfg {Number} bullets show the panel pointer.. default 0
14623 * @cfg {Boolena} autoslide (true|false) auto slide .. default false
14624 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14627 * Create a new TabGroup
14628 * @param {Object} config The config object
14631 Roo.bootstrap.TabGroup = function(config){
14632 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14634 this.navId = Roo.id();
14637 Roo.bootstrap.TabGroup.register(this);
14641 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14644 transition : false,
14650 getAutoCreate : function()
14652 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14654 cfg.cls += ' tab-content';
14656 Roo.log('get auto create...............');
14658 if (this.carousel) {
14659 cfg.cls += ' carousel slide';
14662 cls : 'carousel-inner'
14665 if(this.bullets > 0){
14668 cls : 'carousel-bullets',
14672 for (var i = 0; i < this.bullets; i++){
14674 cls : 'bullet bullet-' + i
14682 cfg.cn[0].cn = bullets;
14689 initEvents: function()
14691 Roo.log('-------- init events on tab group ---------');
14695 if(this.bullets > 0){
14697 for (var i = 0; i < this.bullets; i++){
14698 var bullet = this.el.select('.bullet-' + i, true).first();
14704 bullet.on('click', (function(e, el, o, ii, t){
14706 e.preventDefault();
14708 _this.showPanel(ii);
14710 if(_this.autoslide && _this.slideFn){
14711 clearInterval(_this.slideFn);
14712 _this.slideFn = window.setInterval(function() {
14713 _this.showPanelNext();
14717 }).createDelegate(this, [i, bullet], true));
14721 if(this.autoslide){
14722 this.slideFn = window.setInterval(function() {
14723 _this.showPanelNext();
14728 getChildContainer : function()
14730 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14734 * register a Navigation item
14735 * @param {Roo.bootstrap.NavItem} the navitem to add
14737 register : function(item)
14739 this.tabs.push( item);
14740 item.navId = this.navId; // not really needed..
14744 getActivePanel : function()
14747 Roo.each(this.tabs, function(t) {
14757 getPanelByName : function(n)
14760 Roo.each(this.tabs, function(t) {
14761 if (t.tabId == n) {
14769 indexOfPanel : function(p)
14772 Roo.each(this.tabs, function(t,i) {
14773 if (t.tabId == p.tabId) {
14782 * show a specific panel
14783 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14784 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14786 showPanel : function (pan)
14788 if(this.transition){
14789 Roo.log("waiting for the transitionend");
14793 if (typeof(pan) == 'number') {
14794 pan = this.tabs[pan];
14796 if (typeof(pan) == 'string') {
14797 pan = this.getPanelByName(pan);
14799 if (pan.tabId == this.getActivePanel().tabId) {
14802 var cur = this.getActivePanel();
14804 if (false === cur.fireEvent('beforedeactivate')) {
14808 if(this.bullets > 0){
14809 this.setActiveBullet(this.indexOfPanel(pan));
14812 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14814 this.transition = true;
14815 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14816 var lr = dir == 'next' ? 'left' : 'right';
14817 pan.el.addClass(dir); // or prev
14818 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14819 cur.el.addClass(lr); // or right
14820 pan.el.addClass(lr);
14823 cur.el.on('transitionend', function() {
14824 Roo.log("trans end?");
14826 pan.el.removeClass([lr,dir]);
14827 pan.setActive(true);
14829 cur.el.removeClass([lr]);
14830 cur.setActive(false);
14832 _this.transition = false;
14834 }, this, { single: true } );
14839 cur.setActive(false);
14840 pan.setActive(true);
14845 showPanelNext : function()
14847 var i = this.indexOfPanel(this.getActivePanel());
14849 if (i >= this.tabs.length - 1 && !this.autoslide) {
14853 if (i >= this.tabs.length - 1 && this.autoslide) {
14857 this.showPanel(this.tabs[i+1]);
14860 showPanelPrev : function()
14862 var i = this.indexOfPanel(this.getActivePanel());
14864 if (i < 1 && !this.autoslide) {
14868 if (i < 1 && this.autoslide) {
14869 i = this.tabs.length;
14872 this.showPanel(this.tabs[i-1]);
14875 setActiveBullet : function(i)
14877 Roo.each(this.el.select('.bullet', true).elements, function(el){
14878 el.removeClass('selected');
14881 var bullet = this.el.select('.bullet-' + i, true).first();
14887 bullet.addClass('selected');
14898 Roo.apply(Roo.bootstrap.TabGroup, {
14902 * register a Navigation Group
14903 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14905 register : function(navgrp)
14907 this.groups[navgrp.navId] = navgrp;
14911 * fetch a Navigation Group based on the navigation ID
14912 * if one does not exist , it will get created.
14913 * @param {string} the navgroup to add
14914 * @returns {Roo.bootstrap.NavGroup} the navgroup
14916 get: function(navId) {
14917 if (typeof(this.groups[navId]) == 'undefined') {
14918 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14920 return this.groups[navId] ;
14935 * @class Roo.bootstrap.TabPanel
14936 * @extends Roo.bootstrap.Component
14937 * Bootstrap TabPanel class
14938 * @cfg {Boolean} active panel active
14939 * @cfg {String} html panel content
14940 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14941 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14945 * Create a new TabPanel
14946 * @param {Object} config The config object
14949 Roo.bootstrap.TabPanel = function(config){
14950 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14954 * Fires when the active status changes
14955 * @param {Roo.bootstrap.TabPanel} this
14956 * @param {Boolean} state the new state
14961 * @event beforedeactivate
14962 * Fires before a tab is de-activated - can be used to do validation on a form.
14963 * @param {Roo.bootstrap.TabPanel} this
14964 * @return {Boolean} false if there is an error
14967 'beforedeactivate': true
14970 this.tabId = this.tabId || Roo.id();
14974 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14981 getAutoCreate : function(){
14984 // item is needed for carousel - not sure if it has any effect otherwise
14985 cls: 'tab-pane item',
14986 html: this.html || ''
14990 cfg.cls += ' active';
14994 cfg.tabId = this.tabId;
15001 initEvents: function()
15003 Roo.log('-------- init events on tab panel ---------');
15005 var p = this.parent();
15006 this.navId = this.navId || p.navId;
15008 if (typeof(this.navId) != 'undefined') {
15009 // not really needed.. but just in case.. parent should be a NavGroup.
15010 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15011 Roo.log(['register', tg, this]);
15014 var i = tg.tabs.length - 1;
15016 if(this.active && tg.bullets > 0 && i < tg.bullets){
15017 tg.setActiveBullet(i);
15024 onRender : function(ct, position)
15026 // Roo.log("Call onRender: " + this.xtype);
15028 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15036 setActive: function(state)
15038 Roo.log("panel - set active " + this.tabId + "=" + state);
15040 this.active = state;
15042 this.el.removeClass('active');
15044 } else if (!this.el.hasClass('active')) {
15045 this.el.addClass('active');
15048 this.fireEvent('changed', this, state);
15065 * @class Roo.bootstrap.DateField
15066 * @extends Roo.bootstrap.Input
15067 * Bootstrap DateField class
15068 * @cfg {Number} weekStart default 0
15069 * @cfg {String} viewMode default empty, (months|years)
15070 * @cfg {String} minViewMode default empty, (months|years)
15071 * @cfg {Number} startDate default -Infinity
15072 * @cfg {Number} endDate default Infinity
15073 * @cfg {Boolean} todayHighlight default false
15074 * @cfg {Boolean} todayBtn default false
15075 * @cfg {Boolean} calendarWeeks default false
15076 * @cfg {Object} daysOfWeekDisabled default empty
15077 * @cfg {Boolean} singleMode default false (true | false)
15079 * @cfg {Boolean} keyboardNavigation default true
15080 * @cfg {String} language default en
15083 * Create a new DateField
15084 * @param {Object} config The config object
15087 Roo.bootstrap.DateField = function(config){
15088 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15092 * Fires when this field show.
15093 * @param {Roo.bootstrap.DateField} this
15094 * @param {Mixed} date The date value
15099 * Fires when this field hide.
15100 * @param {Roo.bootstrap.DateField} this
15101 * @param {Mixed} date The date value
15106 * Fires when select a date.
15107 * @param {Roo.bootstrap.DateField} this
15108 * @param {Mixed} date The date value
15114 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15117 * @cfg {String} format
15118 * The default date format string which can be overriden for localization support. The format must be
15119 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15123 * @cfg {String} altFormats
15124 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15125 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15127 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15135 todayHighlight : false,
15141 keyboardNavigation: true,
15143 calendarWeeks: false,
15145 startDate: -Infinity,
15149 daysOfWeekDisabled: [],
15153 singleMode : false,
15155 UTCDate: function()
15157 return new Date(Date.UTC.apply(Date, arguments));
15160 UTCToday: function()
15162 var today = new Date();
15163 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15166 getDate: function() {
15167 var d = this.getUTCDate();
15168 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15171 getUTCDate: function() {
15175 setDate: function(d) {
15176 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15179 setUTCDate: function(d) {
15181 this.setValue(this.formatDate(this.date));
15184 onRender: function(ct, position)
15187 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15189 this.language = this.language || 'en';
15190 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15191 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15193 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15194 this.format = this.format || 'm/d/y';
15195 this.isInline = false;
15196 this.isInput = true;
15197 this.component = this.el.select('.add-on', true).first() || false;
15198 this.component = (this.component && this.component.length === 0) ? false : this.component;
15199 this.hasInput = this.component && this.inputEL().length;
15201 if (typeof(this.minViewMode === 'string')) {
15202 switch (this.minViewMode) {
15204 this.minViewMode = 1;
15207 this.minViewMode = 2;
15210 this.minViewMode = 0;
15215 if (typeof(this.viewMode === 'string')) {
15216 switch (this.viewMode) {
15229 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15231 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15233 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15235 this.picker().on('mousedown', this.onMousedown, this);
15236 this.picker().on('click', this.onClick, this);
15238 this.picker().addClass('datepicker-dropdown');
15240 this.startViewMode = this.viewMode;
15242 if(this.singleMode){
15243 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15244 v.setVisibilityMode(Roo.Element.DISPLAY)
15248 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15249 v.setStyle('width', '189px');
15253 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15254 if(!this.calendarWeeks){
15259 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15260 v.attr('colspan', function(i, val){
15261 return parseInt(val) + 1;
15266 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15268 this.setStartDate(this.startDate);
15269 this.setEndDate(this.endDate);
15271 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15278 if(this.isInline) {
15283 picker : function()
15285 return this.pickerEl;
15286 // return this.el.select('.datepicker', true).first();
15289 fillDow: function()
15291 var dowCnt = this.weekStart;
15300 if(this.calendarWeeks){
15308 while (dowCnt < this.weekStart + 7) {
15312 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15316 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15319 fillMonths: function()
15322 var months = this.picker().select('>.datepicker-months td', true).first();
15324 months.dom.innerHTML = '';
15330 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15333 months.createChild(month);
15340 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;
15342 if (this.date < this.startDate) {
15343 this.viewDate = new Date(this.startDate);
15344 } else if (this.date > this.endDate) {
15345 this.viewDate = new Date(this.endDate);
15347 this.viewDate = new Date(this.date);
15355 var d = new Date(this.viewDate),
15356 year = d.getUTCFullYear(),
15357 month = d.getUTCMonth(),
15358 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15359 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15360 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15361 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15362 currentDate = this.date && this.date.valueOf(),
15363 today = this.UTCToday();
15365 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15367 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15369 // this.picker.select('>tfoot th.today').
15370 // .text(dates[this.language].today)
15371 // .toggle(this.todayBtn !== false);
15373 this.updateNavArrows();
15376 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15378 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15380 prevMonth.setUTCDate(day);
15382 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15384 var nextMonth = new Date(prevMonth);
15386 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15388 nextMonth = nextMonth.valueOf();
15390 var fillMonths = false;
15392 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15394 while(prevMonth.valueOf() < nextMonth) {
15397 if (prevMonth.getUTCDay() === this.weekStart) {
15399 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15407 if(this.calendarWeeks){
15408 // ISO 8601: First week contains first thursday.
15409 // ISO also states week starts on Monday, but we can be more abstract here.
15411 // Start of current week: based on weekstart/current date
15412 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15413 // Thursday of this week
15414 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15415 // First Thursday of year, year from thursday
15416 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15417 // Calendar week: ms between thursdays, div ms per day, div 7 days
15418 calWeek = (th - yth) / 864e5 / 7 + 1;
15420 fillMonths.cn.push({
15428 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15430 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15433 if (this.todayHighlight &&
15434 prevMonth.getUTCFullYear() == today.getFullYear() &&
15435 prevMonth.getUTCMonth() == today.getMonth() &&
15436 prevMonth.getUTCDate() == today.getDate()) {
15437 clsName += ' today';
15440 if (currentDate && prevMonth.valueOf() === currentDate) {
15441 clsName += ' active';
15444 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15445 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15446 clsName += ' disabled';
15449 fillMonths.cn.push({
15451 cls: 'day ' + clsName,
15452 html: prevMonth.getDate()
15455 prevMonth.setDate(prevMonth.getDate()+1);
15458 var currentYear = this.date && this.date.getUTCFullYear();
15459 var currentMonth = this.date && this.date.getUTCMonth();
15461 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15463 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15464 v.removeClass('active');
15466 if(currentYear === year && k === currentMonth){
15467 v.addClass('active');
15470 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15471 v.addClass('disabled');
15477 year = parseInt(year/10, 10) * 10;
15479 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15481 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15484 for (var i = -1; i < 11; i++) {
15485 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15487 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15495 showMode: function(dir)
15498 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15501 Roo.each(this.picker().select('>div',true).elements, function(v){
15502 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15505 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15510 if(this.isInline) return;
15512 this.picker().removeClass(['bottom', 'top']);
15514 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15516 * place to the top of element!
15520 this.picker().addClass('top');
15521 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15526 this.picker().addClass('bottom');
15528 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15531 parseDate : function(value)
15533 if(!value || value instanceof Date){
15536 var v = Date.parseDate(value, this.format);
15537 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15538 v = Date.parseDate(value, 'Y-m-d');
15540 if(!v && this.altFormats){
15541 if(!this.altFormatsArray){
15542 this.altFormatsArray = this.altFormats.split("|");
15544 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15545 v = Date.parseDate(value, this.altFormatsArray[i]);
15551 formatDate : function(date, fmt)
15553 return (!date || !(date instanceof Date)) ?
15554 date : date.dateFormat(fmt || this.format);
15557 onFocus : function()
15559 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15563 onBlur : function()
15565 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15567 var d = this.inputEl().getValue();
15576 this.picker().show();
15580 this.fireEvent('show', this, this.date);
15585 if(this.isInline) return;
15586 this.picker().hide();
15587 this.viewMode = this.startViewMode;
15590 this.fireEvent('hide', this, this.date);
15594 onMousedown: function(e)
15596 e.stopPropagation();
15597 e.preventDefault();
15602 Roo.bootstrap.DateField.superclass.keyup.call(this);
15606 setValue: function(v)
15609 // v can be a string or a date..
15612 var d = new Date(this.parseDate(v) ).clearTime();
15614 if(isNaN(d.getTime())){
15615 this.date = this.viewDate = '';
15616 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15620 v = this.formatDate(d);
15622 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15624 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15628 this.fireEvent('select', this, this.date);
15632 getValue: function()
15634 return this.formatDate(this.date);
15637 fireKey: function(e)
15639 if (!this.picker().isVisible()){
15640 if (e.keyCode == 27) // allow escape to hide and re-show picker
15645 var dateChanged = false,
15647 newDate, newViewDate;
15652 e.preventDefault();
15656 if (!this.keyboardNavigation) break;
15657 dir = e.keyCode == 37 ? -1 : 1;
15660 newDate = this.moveYear(this.date, dir);
15661 newViewDate = this.moveYear(this.viewDate, dir);
15662 } else if (e.shiftKey){
15663 newDate = this.moveMonth(this.date, dir);
15664 newViewDate = this.moveMonth(this.viewDate, dir);
15666 newDate = new Date(this.date);
15667 newDate.setUTCDate(this.date.getUTCDate() + dir);
15668 newViewDate = new Date(this.viewDate);
15669 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15671 if (this.dateWithinRange(newDate)){
15672 this.date = newDate;
15673 this.viewDate = newViewDate;
15674 this.setValue(this.formatDate(this.date));
15676 e.preventDefault();
15677 dateChanged = true;
15682 if (!this.keyboardNavigation) break;
15683 dir = e.keyCode == 38 ? -1 : 1;
15685 newDate = this.moveYear(this.date, dir);
15686 newViewDate = this.moveYear(this.viewDate, dir);
15687 } else if (e.shiftKey){
15688 newDate = this.moveMonth(this.date, dir);
15689 newViewDate = this.moveMonth(this.viewDate, dir);
15691 newDate = new Date(this.date);
15692 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15693 newViewDate = new Date(this.viewDate);
15694 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15696 if (this.dateWithinRange(newDate)){
15697 this.date = newDate;
15698 this.viewDate = newViewDate;
15699 this.setValue(this.formatDate(this.date));
15701 e.preventDefault();
15702 dateChanged = true;
15706 this.setValue(this.formatDate(this.date));
15708 e.preventDefault();
15711 this.setValue(this.formatDate(this.date));
15725 onClick: function(e)
15727 e.stopPropagation();
15728 e.preventDefault();
15730 var target = e.getTarget();
15732 if(target.nodeName.toLowerCase() === 'i'){
15733 target = Roo.get(target).dom.parentNode;
15736 var nodeName = target.nodeName;
15737 var className = target.className;
15738 var html = target.innerHTML;
15739 //Roo.log(nodeName);
15741 switch(nodeName.toLowerCase()) {
15743 switch(className) {
15749 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15750 switch(this.viewMode){
15752 this.viewDate = this.moveMonth(this.viewDate, dir);
15756 this.viewDate = this.moveYear(this.viewDate, dir);
15762 var date = new Date();
15763 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15765 this.setValue(this.formatDate(this.date));
15772 if (className.indexOf('disabled') < 0) {
15773 this.viewDate.setUTCDate(1);
15774 if (className.indexOf('month') > -1) {
15775 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15777 var year = parseInt(html, 10) || 0;
15778 this.viewDate.setUTCFullYear(year);
15782 if(this.singleMode){
15783 this.setValue(this.formatDate(this.viewDate));
15794 //Roo.log(className);
15795 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15796 var day = parseInt(html, 10) || 1;
15797 var year = this.viewDate.getUTCFullYear(),
15798 month = this.viewDate.getUTCMonth();
15800 if (className.indexOf('old') > -1) {
15807 } else if (className.indexOf('new') > -1) {
15815 //Roo.log([year,month,day]);
15816 this.date = this.UTCDate(year, month, day,0,0,0,0);
15817 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15819 //Roo.log(this.formatDate(this.date));
15820 this.setValue(this.formatDate(this.date));
15827 setStartDate: function(startDate)
15829 this.startDate = startDate || -Infinity;
15830 if (this.startDate !== -Infinity) {
15831 this.startDate = this.parseDate(this.startDate);
15834 this.updateNavArrows();
15837 setEndDate: function(endDate)
15839 this.endDate = endDate || Infinity;
15840 if (this.endDate !== Infinity) {
15841 this.endDate = this.parseDate(this.endDate);
15844 this.updateNavArrows();
15847 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15849 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15850 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15851 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15853 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15854 return parseInt(d, 10);
15857 this.updateNavArrows();
15860 updateNavArrows: function()
15862 if(this.singleMode){
15866 var d = new Date(this.viewDate),
15867 year = d.getUTCFullYear(),
15868 month = d.getUTCMonth();
15870 Roo.each(this.picker().select('.prev', true).elements, function(v){
15872 switch (this.viewMode) {
15875 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15881 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15888 Roo.each(this.picker().select('.next', true).elements, function(v){
15890 switch (this.viewMode) {
15893 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15899 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15907 moveMonth: function(date, dir)
15909 if (!dir) return date;
15910 var new_date = new Date(date.valueOf()),
15911 day = new_date.getUTCDate(),
15912 month = new_date.getUTCMonth(),
15913 mag = Math.abs(dir),
15915 dir = dir > 0 ? 1 : -1;
15918 // If going back one month, make sure month is not current month
15919 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15921 return new_date.getUTCMonth() == month;
15923 // If going forward one month, make sure month is as expected
15924 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15926 return new_date.getUTCMonth() != new_month;
15928 new_month = month + dir;
15929 new_date.setUTCMonth(new_month);
15930 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15931 if (new_month < 0 || new_month > 11)
15932 new_month = (new_month + 12) % 12;
15934 // For magnitudes >1, move one month at a time...
15935 for (var i=0; i<mag; i++)
15936 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15937 new_date = this.moveMonth(new_date, dir);
15938 // ...then reset the day, keeping it in the new month
15939 new_month = new_date.getUTCMonth();
15940 new_date.setUTCDate(day);
15942 return new_month != new_date.getUTCMonth();
15945 // Common date-resetting loop -- if date is beyond end of month, make it
15948 new_date.setUTCDate(--day);
15949 new_date.setUTCMonth(new_month);
15954 moveYear: function(date, dir)
15956 return this.moveMonth(date, dir*12);
15959 dateWithinRange: function(date)
15961 return date >= this.startDate && date <= this.endDate;
15967 this.picker().remove();
15972 Roo.apply(Roo.bootstrap.DateField, {
15983 html: '<i class="fa fa-arrow-left"/>'
15993 html: '<i class="fa fa-arrow-right"/>'
16035 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16036 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16037 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16038 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16039 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16052 navFnc: 'FullYear',
16057 navFnc: 'FullYear',
16062 Roo.apply(Roo.bootstrap.DateField, {
16066 cls: 'datepicker dropdown-menu roo-dynamic',
16070 cls: 'datepicker-days',
16074 cls: 'table-condensed',
16076 Roo.bootstrap.DateField.head,
16080 Roo.bootstrap.DateField.footer
16087 cls: 'datepicker-months',
16091 cls: 'table-condensed',
16093 Roo.bootstrap.DateField.head,
16094 Roo.bootstrap.DateField.content,
16095 Roo.bootstrap.DateField.footer
16102 cls: 'datepicker-years',
16106 cls: 'table-condensed',
16108 Roo.bootstrap.DateField.head,
16109 Roo.bootstrap.DateField.content,
16110 Roo.bootstrap.DateField.footer
16129 * @class Roo.bootstrap.TimeField
16130 * @extends Roo.bootstrap.Input
16131 * Bootstrap DateField class
16135 * Create a new TimeField
16136 * @param {Object} config The config object
16139 Roo.bootstrap.TimeField = function(config){
16140 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16144 * Fires when this field show.
16145 * @param {Roo.bootstrap.DateField} thisthis
16146 * @param {Mixed} date The date value
16151 * Fires when this field hide.
16152 * @param {Roo.bootstrap.DateField} this
16153 * @param {Mixed} date The date value
16158 * Fires when select a date.
16159 * @param {Roo.bootstrap.DateField} this
16160 * @param {Mixed} date The date value
16166 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16169 * @cfg {String} format
16170 * The default time format string which can be overriden for localization support. The format must be
16171 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16175 onRender: function(ct, position)
16178 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16180 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16182 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16184 this.pop = this.picker().select('>.datepicker-time',true).first();
16185 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16187 this.picker().on('mousedown', this.onMousedown, this);
16188 this.picker().on('click', this.onClick, this);
16190 this.picker().addClass('datepicker-dropdown');
16195 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16196 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16197 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16198 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16199 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16200 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16204 fireKey: function(e){
16205 if (!this.picker().isVisible()){
16206 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16212 e.preventDefault();
16220 this.onTogglePeriod();
16223 this.onIncrementMinutes();
16226 this.onDecrementMinutes();
16235 onClick: function(e) {
16236 e.stopPropagation();
16237 e.preventDefault();
16240 picker : function()
16242 return this.el.select('.datepicker', true).first();
16245 fillTime: function()
16247 var time = this.pop.select('tbody', true).first();
16249 time.dom.innerHTML = '';
16264 cls: 'hours-up glyphicon glyphicon-chevron-up'
16284 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16305 cls: 'timepicker-hour',
16320 cls: 'timepicker-minute',
16335 cls: 'btn btn-primary period',
16357 cls: 'hours-down glyphicon glyphicon-chevron-down'
16377 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16395 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16402 var hours = this.time.getHours();
16403 var minutes = this.time.getMinutes();
16416 hours = hours - 12;
16420 hours = '0' + hours;
16424 minutes = '0' + minutes;
16427 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16428 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16429 this.pop.select('button', true).first().dom.innerHTML = period;
16435 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16437 var cls = ['bottom'];
16439 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16446 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16451 this.picker().addClass(cls.join('-'));
16455 Roo.each(cls, function(c){
16457 _this.picker().setTop(_this.inputEl().getHeight());
16461 _this.picker().setTop(0 - _this.picker().getHeight());
16466 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16470 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16477 onFocus : function()
16479 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16483 onBlur : function()
16485 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16491 this.picker().show();
16496 this.fireEvent('show', this, this.date);
16501 this.picker().hide();
16504 this.fireEvent('hide', this, this.date);
16507 setTime : function()
16510 this.setValue(this.time.format(this.format));
16512 this.fireEvent('select', this, this.date);
16517 onMousedown: function(e){
16518 e.stopPropagation();
16519 e.preventDefault();
16522 onIncrementHours: function()
16524 Roo.log('onIncrementHours');
16525 this.time = this.time.add(Date.HOUR, 1);
16530 onDecrementHours: function()
16532 Roo.log('onDecrementHours');
16533 this.time = this.time.add(Date.HOUR, -1);
16537 onIncrementMinutes: function()
16539 Roo.log('onIncrementMinutes');
16540 this.time = this.time.add(Date.MINUTE, 1);
16544 onDecrementMinutes: function()
16546 Roo.log('onDecrementMinutes');
16547 this.time = this.time.add(Date.MINUTE, -1);
16551 onTogglePeriod: function()
16553 Roo.log('onTogglePeriod');
16554 this.time = this.time.add(Date.HOUR, 12);
16561 Roo.apply(Roo.bootstrap.TimeField, {
16591 cls: 'btn btn-info ok',
16603 Roo.apply(Roo.bootstrap.TimeField, {
16607 cls: 'datepicker dropdown-menu',
16611 cls: 'datepicker-time',
16615 cls: 'table-condensed',
16617 Roo.bootstrap.TimeField.content,
16618 Roo.bootstrap.TimeField.footer
16637 * @class Roo.bootstrap.MonthField
16638 * @extends Roo.bootstrap.Input
16639 * Bootstrap MonthField class
16641 * @cfg {String} language default en
16644 * Create a new MonthField
16645 * @param {Object} config The config object
16648 Roo.bootstrap.MonthField = function(config){
16649 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16654 * Fires when this field show.
16655 * @param {Roo.bootstrap.MonthField} this
16656 * @param {Mixed} date The date value
16661 * Fires when this field hide.
16662 * @param {Roo.bootstrap.MonthField} this
16663 * @param {Mixed} date The date value
16668 * Fires when select a date.
16669 * @param {Roo.bootstrap.MonthField} this
16670 * @param {String} oldvalue The old value
16671 * @param {String} newvalue The new value
16677 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16679 onRender: function(ct, position)
16682 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16684 this.language = this.language || 'en';
16685 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16686 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16688 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16689 this.isInline = false;
16690 this.isInput = true;
16691 this.component = this.el.select('.add-on', true).first() || false;
16692 this.component = (this.component && this.component.length === 0) ? false : this.component;
16693 this.hasInput = this.component && this.inputEL().length;
16695 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16697 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16699 this.picker().on('mousedown', this.onMousedown, this);
16700 this.picker().on('click', this.onClick, this);
16702 this.picker().addClass('datepicker-dropdown');
16704 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16705 v.setStyle('width', '189px');
16712 if(this.isInline) {
16718 setValue: function(v, suppressEvent)
16720 var o = this.getValue();
16722 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16726 if(suppressEvent !== true){
16727 this.fireEvent('select', this, o, v);
16732 getValue: function()
16737 onClick: function(e)
16739 e.stopPropagation();
16740 e.preventDefault();
16742 var target = e.getTarget();
16744 if(target.nodeName.toLowerCase() === 'i'){
16745 target = Roo.get(target).dom.parentNode;
16748 var nodeName = target.nodeName;
16749 var className = target.className;
16750 var html = target.innerHTML;
16752 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16756 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16758 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16764 picker : function()
16766 return this.pickerEl;
16769 fillMonths: function()
16772 var months = this.picker().select('>.datepicker-months td', true).first();
16774 months.dom.innerHTML = '';
16780 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16783 months.createChild(month);
16792 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16793 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16796 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16797 e.removeClass('active');
16799 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16800 e.addClass('active');
16807 if(this.isInline) return;
16809 this.picker().removeClass(['bottom', 'top']);
16811 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16813 * place to the top of element!
16817 this.picker().addClass('top');
16818 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16823 this.picker().addClass('bottom');
16825 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16828 onFocus : function()
16830 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16834 onBlur : function()
16836 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16838 var d = this.inputEl().getValue();
16847 this.picker().show();
16848 this.picker().select('>.datepicker-months', true).first().show();
16852 this.fireEvent('show', this, this.date);
16857 if(this.isInline) return;
16858 this.picker().hide();
16859 this.fireEvent('hide', this, this.date);
16863 onMousedown: function(e)
16865 e.stopPropagation();
16866 e.preventDefault();
16871 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16875 fireKey: function(e)
16877 if (!this.picker().isVisible()){
16878 if (e.keyCode == 27) // allow escape to hide and re-show picker
16888 e.preventDefault();
16892 dir = e.keyCode == 37 ? -1 : 1;
16894 this.vIndex = this.vIndex + dir;
16896 if(this.vIndex < 0){
16900 if(this.vIndex > 11){
16904 if(isNaN(this.vIndex)){
16908 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16914 dir = e.keyCode == 38 ? -1 : 1;
16916 this.vIndex = this.vIndex + dir * 4;
16918 if(this.vIndex < 0){
16922 if(this.vIndex > 11){
16926 if(isNaN(this.vIndex)){
16930 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16935 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16936 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16940 e.preventDefault();
16943 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16944 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16960 this.picker().remove();
16965 Roo.apply(Roo.bootstrap.MonthField, {
16984 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16985 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16990 Roo.apply(Roo.bootstrap.MonthField, {
16994 cls: 'datepicker dropdown-menu roo-dynamic',
16998 cls: 'datepicker-months',
17002 cls: 'table-condensed',
17004 Roo.bootstrap.DateField.content
17024 * @class Roo.bootstrap.CheckBox
17025 * @extends Roo.bootstrap.Input
17026 * Bootstrap CheckBox class
17028 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17029 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17030 * @cfg {String} boxLabel The text that appears beside the checkbox
17031 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17032 * @cfg {Boolean} checked initnal the element
17033 * @cfg {Boolean} inline inline the element (default false)
17034 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17037 * Create a new CheckBox
17038 * @param {Object} config The config object
17041 Roo.bootstrap.CheckBox = function(config){
17042 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17047 * Fires when the element is checked or unchecked.
17048 * @param {Roo.bootstrap.CheckBox} this This input
17049 * @param {Boolean} checked The new checked value
17056 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17058 inputType: 'checkbox',
17066 getAutoCreate : function()
17068 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17074 cfg.cls = 'form-group ' + this.inputType; //input-group
17077 cfg.cls += ' ' + this.inputType + '-inline';
17083 type : this.inputType,
17084 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17085 cls : 'roo-' + this.inputType, //'form-box',
17086 placeholder : this.placeholder || ''
17090 if (this.weight) { // Validity check?
17091 cfg.cls += " " + this.inputType + "-" + this.weight;
17094 if (this.disabled) {
17095 input.disabled=true;
17099 input.checked = this.checked;
17103 input.name = this.name;
17107 input.cls += ' input-' + this.size;
17112 ['xs','sm','md','lg'].map(function(size){
17113 if (settings[size]) {
17114 cfg.cls += ' col-' + size + '-' + settings[size];
17118 var inputblock = input;
17120 if (this.before || this.after) {
17123 cls : 'input-group',
17128 inputblock.cn.push({
17130 cls : 'input-group-addon',
17135 inputblock.cn.push(input);
17138 inputblock.cn.push({
17140 cls : 'input-group-addon',
17147 if (align ==='left' && this.fieldLabel.length) {
17148 Roo.log("left and has label");
17154 cls : 'control-label col-md-' + this.labelWidth,
17155 html : this.fieldLabel
17159 cls : "col-md-" + (12 - this.labelWidth),
17166 } else if ( this.fieldLabel.length) {
17171 tag: this.boxLabel ? 'span' : 'label',
17173 cls: 'control-label box-input-label',
17174 //cls : 'input-group-addon',
17175 html : this.fieldLabel
17185 Roo.log(" no label && no align");
17186 cfg.cn = [ inputblock ] ;
17191 var boxLabelCfg = {
17193 //'for': id, // box label is handled by onclick - so no for...
17195 html: this.boxLabel
17199 boxLabelCfg.tooltip = this.tooltip;
17202 cfg.cn.push(boxLabelCfg);
17212 * return the real input element.
17214 inputEl: function ()
17216 return this.el.select('input.roo-' + this.inputType,true).first();
17219 labelEl: function()
17221 return this.el.select('label.control-label',true).first();
17223 /* depricated... */
17227 return this.labelEl();
17230 initEvents : function()
17232 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17234 this.inputEl().on('click', this.onClick, this);
17236 if (this.boxLabel) {
17237 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17240 this.startValue = this.getValue();
17243 Roo.bootstrap.CheckBox.register(this);
17247 onClick : function()
17249 this.setChecked(!this.checked);
17252 setChecked : function(state,suppressEvent)
17254 this.startValue = this.getValue();
17256 if(this.inputType == 'radio'){
17258 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17259 e.dom.checked = false;
17262 this.inputEl().dom.checked = true;
17264 this.inputEl().dom.value = this.inputValue;
17266 if(suppressEvent !== true){
17267 this.fireEvent('check', this, true);
17275 this.checked = state;
17277 this.inputEl().dom.checked = state;
17279 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17281 if(suppressEvent !== true){
17282 this.fireEvent('check', this, state);
17288 getValue : function()
17290 if(this.inputType == 'radio'){
17291 return this.getGroupValue();
17294 return this.inputEl().getValue();
17298 getGroupValue : function()
17300 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17304 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17307 setValue : function(v,suppressEvent)
17309 if(this.inputType == 'radio'){
17310 this.setGroupValue(v, suppressEvent);
17314 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17319 setGroupValue : function(v, suppressEvent)
17321 this.startValue = this.getValue();
17323 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17324 e.dom.checked = false;
17326 if(e.dom.value == v){
17327 e.dom.checked = true;
17331 if(suppressEvent !== true){
17332 this.fireEvent('check', this, true);
17340 validate : function()
17344 (this.inputType == 'radio' && this.validateRadio()) ||
17345 (this.inputType == 'checkbox' && this.validateCheckbox())
17351 this.markInvalid();
17355 validateRadio : function()
17359 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17360 if(!e.dom.checked){
17372 validateCheckbox : function()
17375 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17378 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17386 for(var i in group){
17391 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17398 * Mark this field as valid
17400 markValid : function()
17402 if(this.allowBlank){
17408 this.fireEvent('valid', this);
17410 if(this.inputType == 'radio'){
17411 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17412 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17413 e.findParent('.form-group', false, true).addClass(_this.validClass);
17420 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17421 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17425 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17431 for(var i in group){
17432 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17433 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17438 * Mark this field as invalid
17439 * @param {String} msg The validation message
17441 markInvalid : function(msg)
17443 if(this.allowBlank){
17449 this.fireEvent('invalid', this, msg);
17451 if(this.inputType == 'radio'){
17452 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17453 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17454 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17461 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17462 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17466 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17472 for(var i in group){
17473 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17474 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17481 Roo.apply(Roo.bootstrap.CheckBox, {
17486 * register a CheckBox Group
17487 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17489 register : function(checkbox)
17491 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17492 this.groups[checkbox.groupId] = {};
17495 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17499 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17503 * fetch a CheckBox Group based on the group ID
17504 * @param {string} the group ID
17505 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17507 get: function(groupId) {
17508 if (typeof(this.groups[groupId]) == 'undefined') {
17512 return this.groups[groupId] ;
17524 *<div class="radio">
17526 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17527 Option one is this and that—be sure to include why it's great
17534 *<label class="radio-inline">fieldLabel</label>
17535 *<label class="radio-inline">
17536 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17544 * @class Roo.bootstrap.Radio
17545 * @extends Roo.bootstrap.CheckBox
17546 * Bootstrap Radio class
17549 * Create a new Radio
17550 * @param {Object} config The config object
17553 Roo.bootstrap.Radio = function(config){
17554 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17558 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17560 inputType: 'radio',
17564 getAutoCreate : function()
17566 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17567 align = align || 'left'; // default...
17574 tag : this.inline ? 'span' : 'div',
17579 var inline = this.inline ? ' radio-inline' : '';
17583 // does not need for, as we wrap the input with it..
17585 cls : 'control-label box-label' + inline,
17588 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17592 //cls : 'control-label' + inline,
17593 html : this.fieldLabel,
17594 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17603 type : this.inputType,
17604 //value : (!this.checked) ? this.valueOff : this.inputValue,
17605 value : this.inputValue,
17607 placeholder : this.placeholder || '' // ?? needed????
17610 if (this.weight) { // Validity check?
17611 input.cls += " radio-" + this.weight;
17613 if (this.disabled) {
17614 input.disabled=true;
17618 input.checked = this.checked;
17622 input.name = this.name;
17626 input.cls += ' input-' + this.size;
17629 //?? can span's inline have a width??
17632 ['xs','sm','md','lg'].map(function(size){
17633 if (settings[size]) {
17634 cfg.cls += ' col-' + size + '-' + settings[size];
17638 var inputblock = input;
17640 if (this.before || this.after) {
17643 cls : 'input-group',
17648 inputblock.cn.push({
17650 cls : 'input-group-addon',
17654 inputblock.cn.push(input);
17656 inputblock.cn.push({
17658 cls : 'input-group-addon',
17666 if (this.fieldLabel && this.fieldLabel.length) {
17667 cfg.cn.push(fieldLabel);
17670 // normal bootstrap puts the input inside the label.
17671 // however with our styled version - it has to go after the input.
17673 //lbl.cn.push(inputblock);
17677 cls: 'radio' + inline,
17684 cfg.cn.push( lblwrap);
17689 html: this.boxLabel
17698 initEvents : function()
17700 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17702 this.inputEl().on('click', this.onClick, this);
17703 if (this.boxLabel) {
17704 Roo.log('find label')
17705 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17710 inputEl: function ()
17712 return this.el.select('input.roo-radio',true).first();
17714 onClick : function()
17717 this.setChecked(true);
17720 setChecked : function(state,suppressEvent)
17723 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17724 v.dom.checked = false;
17727 Roo.log(this.inputEl().dom);
17728 this.checked = state;
17729 this.inputEl().dom.checked = state;
17731 if(suppressEvent !== true){
17732 this.fireEvent('check', this, state);
17735 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17739 getGroupValue : function()
17742 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17743 if(v.dom.checked == true){
17744 value = v.dom.value;
17752 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17753 * @return {Mixed} value The field value
17755 getValue : function(){
17756 return this.getGroupValue();
17762 //<script type="text/javascript">
17765 * Based Ext JS Library 1.1.1
17766 * Copyright(c) 2006-2007, Ext JS, LLC.
17772 * @class Roo.HtmlEditorCore
17773 * @extends Roo.Component
17774 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17776 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17779 Roo.HtmlEditorCore = function(config){
17782 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17787 * @event initialize
17788 * Fires when the editor is fully initialized (including the iframe)
17789 * @param {Roo.HtmlEditorCore} this
17794 * Fires when the editor is first receives the focus. Any insertion must wait
17795 * until after this event.
17796 * @param {Roo.HtmlEditorCore} this
17800 * @event beforesync
17801 * Fires before the textarea is updated with content from the editor iframe. Return false
17802 * to cancel the sync.
17803 * @param {Roo.HtmlEditorCore} this
17804 * @param {String} html
17808 * @event beforepush
17809 * Fires before the iframe editor is updated with content from the textarea. Return false
17810 * to cancel the push.
17811 * @param {Roo.HtmlEditorCore} this
17812 * @param {String} html
17817 * Fires when the textarea is updated with content from the editor iframe.
17818 * @param {Roo.HtmlEditorCore} this
17819 * @param {String} html
17824 * Fires when the iframe editor is updated with content from the textarea.
17825 * @param {Roo.HtmlEditorCore} this
17826 * @param {String} html
17831 * @event editorevent
17832 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17833 * @param {Roo.HtmlEditorCore} this
17839 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17841 // defaults : white / black...
17842 this.applyBlacklists();
17849 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17853 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17859 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17864 * @cfg {Number} height (in pixels)
17868 * @cfg {Number} width (in pixels)
17873 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17876 stylesheets: false,
17881 // private properties
17882 validationEvent : false,
17884 initialized : false,
17886 sourceEditMode : false,
17887 onFocus : Roo.emptyFn,
17889 hideMode:'offsets',
17893 // blacklist + whitelisted elements..
17900 * Protected method that will not generally be called directly. It
17901 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17902 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17904 getDocMarkup : function(){
17908 // inherit styels from page...??
17909 if (this.stylesheets === false) {
17911 Roo.get(document.head).select('style').each(function(node) {
17912 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17915 Roo.get(document.head).select('link').each(function(node) {
17916 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17919 } else if (!this.stylesheets.length) {
17921 st = '<style type="text/css">' +
17922 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17928 st += '<style type="text/css">' +
17929 'IMG { cursor: pointer } ' +
17933 return '<html><head>' + st +
17934 //<style type="text/css">' +
17935 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17937 ' </head><body class="roo-htmleditor-body"></body></html>';
17941 onRender : function(ct, position)
17944 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17945 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17948 this.el.dom.style.border = '0 none';
17949 this.el.dom.setAttribute('tabIndex', -1);
17950 this.el.addClass('x-hidden hide');
17954 if(Roo.isIE){ // fix IE 1px bogus margin
17955 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17959 this.frameId = Roo.id();
17963 var iframe = this.owner.wrap.createChild({
17965 cls: 'form-control', // bootstrap..
17967 name: this.frameId,
17968 frameBorder : 'no',
17969 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17974 this.iframe = iframe.dom;
17976 this.assignDocWin();
17978 this.doc.designMode = 'on';
17981 this.doc.write(this.getDocMarkup());
17985 var task = { // must defer to wait for browser to be ready
17987 //console.log("run task?" + this.doc.readyState);
17988 this.assignDocWin();
17989 if(this.doc.body || this.doc.readyState == 'complete'){
17991 this.doc.designMode="on";
17995 Roo.TaskMgr.stop(task);
17996 this.initEditor.defer(10, this);
18003 Roo.TaskMgr.start(task);
18008 onResize : function(w, h)
18010 Roo.log('resize: ' +w + ',' + h );
18011 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18015 if(typeof w == 'number'){
18017 this.iframe.style.width = w + 'px';
18019 if(typeof h == 'number'){
18021 this.iframe.style.height = h + 'px';
18023 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18030 * Toggles the editor between standard and source edit mode.
18031 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18033 toggleSourceEdit : function(sourceEditMode){
18035 this.sourceEditMode = sourceEditMode === true;
18037 if(this.sourceEditMode){
18039 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18042 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18043 //this.iframe.className = '';
18046 //this.setSize(this.owner.wrap.getSize());
18047 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18054 * Protected method that will not generally be called directly. If you need/want
18055 * custom HTML cleanup, this is the method you should override.
18056 * @param {String} html The HTML to be cleaned
18057 * return {String} The cleaned HTML
18059 cleanHtml : function(html){
18060 html = String(html);
18061 if(html.length > 5){
18062 if(Roo.isSafari){ // strip safari nonsense
18063 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18066 if(html == ' '){
18073 * HTML Editor -> Textarea
18074 * Protected method that will not generally be called directly. Syncs the contents
18075 * of the editor iframe with the textarea.
18077 syncValue : function(){
18078 if(this.initialized){
18079 var bd = (this.doc.body || this.doc.documentElement);
18080 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18081 var html = bd.innerHTML;
18083 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18084 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18086 html = '<div style="'+m[0]+'">' + html + '</div>';
18089 html = this.cleanHtml(html);
18090 // fix up the special chars.. normaly like back quotes in word...
18091 // however we do not want to do this with chinese..
18092 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18093 var cc = b.charCodeAt();
18095 (cc >= 0x4E00 && cc < 0xA000 ) ||
18096 (cc >= 0x3400 && cc < 0x4E00 ) ||
18097 (cc >= 0xf900 && cc < 0xfb00 )
18103 if(this.owner.fireEvent('beforesync', this, html) !== false){
18104 this.el.dom.value = html;
18105 this.owner.fireEvent('sync', this, html);
18111 * Protected method that will not generally be called directly. Pushes the value of the textarea
18112 * into the iframe editor.
18114 pushValue : function(){
18115 if(this.initialized){
18116 var v = this.el.dom.value.trim();
18118 // if(v.length < 1){
18122 if(this.owner.fireEvent('beforepush', this, v) !== false){
18123 var d = (this.doc.body || this.doc.documentElement);
18125 this.cleanUpPaste();
18126 this.el.dom.value = d.innerHTML;
18127 this.owner.fireEvent('push', this, v);
18133 deferFocus : function(){
18134 this.focus.defer(10, this);
18138 focus : function(){
18139 if(this.win && !this.sourceEditMode){
18146 assignDocWin: function()
18148 var iframe = this.iframe;
18151 this.doc = iframe.contentWindow.document;
18152 this.win = iframe.contentWindow;
18154 // if (!Roo.get(this.frameId)) {
18157 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18158 // this.win = Roo.get(this.frameId).dom.contentWindow;
18160 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18164 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18165 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18170 initEditor : function(){
18171 //console.log("INIT EDITOR");
18172 this.assignDocWin();
18176 this.doc.designMode="on";
18178 this.doc.write(this.getDocMarkup());
18181 var dbody = (this.doc.body || this.doc.documentElement);
18182 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18183 // this copies styles from the containing element into thsi one..
18184 // not sure why we need all of this..
18185 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18187 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18188 //ss['background-attachment'] = 'fixed'; // w3c
18189 dbody.bgProperties = 'fixed'; // ie
18190 //Roo.DomHelper.applyStyles(dbody, ss);
18191 Roo.EventManager.on(this.doc, {
18192 //'mousedown': this.onEditorEvent,
18193 'mouseup': this.onEditorEvent,
18194 'dblclick': this.onEditorEvent,
18195 'click': this.onEditorEvent,
18196 'keyup': this.onEditorEvent,
18201 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18203 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18204 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18206 this.initialized = true;
18208 this.owner.fireEvent('initialize', this);
18213 onDestroy : function(){
18219 //for (var i =0; i < this.toolbars.length;i++) {
18220 // // fixme - ask toolbars for heights?
18221 // this.toolbars[i].onDestroy();
18224 //this.wrap.dom.innerHTML = '';
18225 //this.wrap.remove();
18230 onFirstFocus : function(){
18232 this.assignDocWin();
18235 this.activated = true;
18238 if(Roo.isGecko){ // prevent silly gecko errors
18240 var s = this.win.getSelection();
18241 if(!s.focusNode || s.focusNode.nodeType != 3){
18242 var r = s.getRangeAt(0);
18243 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18248 this.execCmd('useCSS', true);
18249 this.execCmd('styleWithCSS', false);
18252 this.owner.fireEvent('activate', this);
18256 adjustFont: function(btn){
18257 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18258 //if(Roo.isSafari){ // safari
18261 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18262 if(Roo.isSafari){ // safari
18263 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18264 v = (v < 10) ? 10 : v;
18265 v = (v > 48) ? 48 : v;
18266 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18271 v = Math.max(1, v+adjust);
18273 this.execCmd('FontSize', v );
18276 onEditorEvent : function(e){
18277 this.owner.fireEvent('editorevent', this, e);
18278 // this.updateToolbar();
18279 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18282 insertTag : function(tg)
18284 // could be a bit smarter... -> wrap the current selected tRoo..
18285 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18287 range = this.createRange(this.getSelection());
18288 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18289 wrappingNode.appendChild(range.extractContents());
18290 range.insertNode(wrappingNode);
18297 this.execCmd("formatblock", tg);
18301 insertText : function(txt)
18305 var range = this.createRange();
18306 range.deleteContents();
18307 //alert(Sender.getAttribute('label'));
18309 range.insertNode(this.doc.createTextNode(txt));
18315 * Executes a Midas editor command on the editor document and performs necessary focus and
18316 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18317 * @param {String} cmd The Midas command
18318 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18320 relayCmd : function(cmd, value){
18322 this.execCmd(cmd, value);
18323 this.owner.fireEvent('editorevent', this);
18324 //this.updateToolbar();
18325 this.owner.deferFocus();
18329 * Executes a Midas editor command directly on the editor document.
18330 * For visual commands, you should use {@link #relayCmd} instead.
18331 * <b>This should only be called after the editor is initialized.</b>
18332 * @param {String} cmd The Midas command
18333 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18335 execCmd : function(cmd, value){
18336 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18343 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18345 * @param {String} text | dom node..
18347 insertAtCursor : function(text)
18352 if(!this.activated){
18358 var r = this.doc.selection.createRange();
18369 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18373 // from jquery ui (MIT licenced)
18375 var win = this.win;
18377 if (win.getSelection && win.getSelection().getRangeAt) {
18378 range = win.getSelection().getRangeAt(0);
18379 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18380 range.insertNode(node);
18381 } else if (win.document.selection && win.document.selection.createRange) {
18382 // no firefox support
18383 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18384 win.document.selection.createRange().pasteHTML(txt);
18386 // no firefox support
18387 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18388 this.execCmd('InsertHTML', txt);
18397 mozKeyPress : function(e){
18399 var c = e.getCharCode(), cmd;
18402 c = String.fromCharCode(c).toLowerCase();
18416 this.cleanUpPaste.defer(100, this);
18424 e.preventDefault();
18432 fixKeys : function(){ // load time branching for fastest keydown performance
18434 return function(e){
18435 var k = e.getKey(), r;
18438 r = this.doc.selection.createRange();
18441 r.pasteHTML('    ');
18448 r = this.doc.selection.createRange();
18450 var target = r.parentElement();
18451 if(!target || target.tagName.toLowerCase() != 'li'){
18453 r.pasteHTML('<br />');
18459 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18460 this.cleanUpPaste.defer(100, this);
18466 }else if(Roo.isOpera){
18467 return function(e){
18468 var k = e.getKey();
18472 this.execCmd('InsertHTML','    ');
18475 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18476 this.cleanUpPaste.defer(100, this);
18481 }else if(Roo.isSafari){
18482 return function(e){
18483 var k = e.getKey();
18487 this.execCmd('InsertText','\t');
18491 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18492 this.cleanUpPaste.defer(100, this);
18500 getAllAncestors: function()
18502 var p = this.getSelectedNode();
18505 a.push(p); // push blank onto stack..
18506 p = this.getParentElement();
18510 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18514 a.push(this.doc.body);
18518 lastSelNode : false,
18521 getSelection : function()
18523 this.assignDocWin();
18524 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18527 getSelectedNode: function()
18529 // this may only work on Gecko!!!
18531 // should we cache this!!!!
18536 var range = this.createRange(this.getSelection()).cloneRange();
18539 var parent = range.parentElement();
18541 var testRange = range.duplicate();
18542 testRange.moveToElementText(parent);
18543 if (testRange.inRange(range)) {
18546 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18549 parent = parent.parentElement;
18554 // is ancestor a text element.
18555 var ac = range.commonAncestorContainer;
18556 if (ac.nodeType == 3) {
18557 ac = ac.parentNode;
18560 var ar = ac.childNodes;
18563 var other_nodes = [];
18564 var has_other_nodes = false;
18565 for (var i=0;i<ar.length;i++) {
18566 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18569 // fullly contained node.
18571 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18576 // probably selected..
18577 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18578 other_nodes.push(ar[i]);
18582 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18587 has_other_nodes = true;
18589 if (!nodes.length && other_nodes.length) {
18590 nodes= other_nodes;
18592 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18598 createRange: function(sel)
18600 // this has strange effects when using with
18601 // top toolbar - not sure if it's a great idea.
18602 //this.editor.contentWindow.focus();
18603 if (typeof sel != "undefined") {
18605 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18607 return this.doc.createRange();
18610 return this.doc.createRange();
18613 getParentElement: function()
18616 this.assignDocWin();
18617 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18619 var range = this.createRange(sel);
18622 var p = range.commonAncestorContainer;
18623 while (p.nodeType == 3) { // text node
18634 * Range intersection.. the hard stuff...
18638 * [ -- selected range --- ]
18642 * if end is before start or hits it. fail.
18643 * if start is after end or hits it fail.
18645 * if either hits (but other is outside. - then it's not
18651 // @see http://www.thismuchiknow.co.uk/?p=64.
18652 rangeIntersectsNode : function(range, node)
18654 var nodeRange = node.ownerDocument.createRange();
18656 nodeRange.selectNode(node);
18658 nodeRange.selectNodeContents(node);
18661 var rangeStartRange = range.cloneRange();
18662 rangeStartRange.collapse(true);
18664 var rangeEndRange = range.cloneRange();
18665 rangeEndRange.collapse(false);
18667 var nodeStartRange = nodeRange.cloneRange();
18668 nodeStartRange.collapse(true);
18670 var nodeEndRange = nodeRange.cloneRange();
18671 nodeEndRange.collapse(false);
18673 return rangeStartRange.compareBoundaryPoints(
18674 Range.START_TO_START, nodeEndRange) == -1 &&
18675 rangeEndRange.compareBoundaryPoints(
18676 Range.START_TO_START, nodeStartRange) == 1;
18680 rangeCompareNode : function(range, node)
18682 var nodeRange = node.ownerDocument.createRange();
18684 nodeRange.selectNode(node);
18686 nodeRange.selectNodeContents(node);
18690 range.collapse(true);
18692 nodeRange.collapse(true);
18694 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18695 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18697 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18699 var nodeIsBefore = ss == 1;
18700 var nodeIsAfter = ee == -1;
18702 if (nodeIsBefore && nodeIsAfter)
18704 if (!nodeIsBefore && nodeIsAfter)
18705 return 1; //right trailed.
18707 if (nodeIsBefore && !nodeIsAfter)
18708 return 2; // left trailed.
18713 // private? - in a new class?
18714 cleanUpPaste : function()
18716 // cleans up the whole document..
18717 Roo.log('cleanuppaste');
18719 this.cleanUpChildren(this.doc.body);
18720 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18721 if (clean != this.doc.body.innerHTML) {
18722 this.doc.body.innerHTML = clean;
18727 cleanWordChars : function(input) {// change the chars to hex code
18728 var he = Roo.HtmlEditorCore;
18730 var output = input;
18731 Roo.each(he.swapCodes, function(sw) {
18732 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18734 output = output.replace(swapper, sw[1]);
18741 cleanUpChildren : function (n)
18743 if (!n.childNodes.length) {
18746 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18747 this.cleanUpChild(n.childNodes[i]);
18754 cleanUpChild : function (node)
18757 //console.log(node);
18758 if (node.nodeName == "#text") {
18759 // clean up silly Windows -- stuff?
18762 if (node.nodeName == "#comment") {
18763 node.parentNode.removeChild(node);
18764 // clean up silly Windows -- stuff?
18767 var lcname = node.tagName.toLowerCase();
18768 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18769 // whitelist of tags..
18771 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18773 node.parentNode.removeChild(node);
18778 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18780 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18781 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18783 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18784 // remove_keep_children = true;
18787 if (remove_keep_children) {
18788 this.cleanUpChildren(node);
18789 // inserts everything just before this node...
18790 while (node.childNodes.length) {
18791 var cn = node.childNodes[0];
18792 node.removeChild(cn);
18793 node.parentNode.insertBefore(cn, node);
18795 node.parentNode.removeChild(node);
18799 if (!node.attributes || !node.attributes.length) {
18800 this.cleanUpChildren(node);
18804 function cleanAttr(n,v)
18807 if (v.match(/^\./) || v.match(/^\//)) {
18810 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18813 if (v.match(/^#/)) {
18816 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18817 node.removeAttribute(n);
18821 var cwhite = this.cwhite;
18822 var cblack = this.cblack;
18824 function cleanStyle(n,v)
18826 if (v.match(/expression/)) { //XSS?? should we even bother..
18827 node.removeAttribute(n);
18831 var parts = v.split(/;/);
18834 Roo.each(parts, function(p) {
18835 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18839 var l = p.split(':').shift().replace(/\s+/g,'');
18840 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18842 if ( cwhite.length && cblack.indexOf(l) > -1) {
18843 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18844 //node.removeAttribute(n);
18848 // only allow 'c whitelisted system attributes'
18849 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18850 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18851 //node.removeAttribute(n);
18861 if (clean.length) {
18862 node.setAttribute(n, clean.join(';'));
18864 node.removeAttribute(n);
18870 for (var i = node.attributes.length-1; i > -1 ; i--) {
18871 var a = node.attributes[i];
18874 if (a.name.toLowerCase().substr(0,2)=='on') {
18875 node.removeAttribute(a.name);
18878 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18879 node.removeAttribute(a.name);
18882 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18883 cleanAttr(a.name,a.value); // fixme..
18886 if (a.name == 'style') {
18887 cleanStyle(a.name,a.value);
18890 /// clean up MS crap..
18891 // tecnically this should be a list of valid class'es..
18894 if (a.name == 'class') {
18895 if (a.value.match(/^Mso/)) {
18896 node.className = '';
18899 if (a.value.match(/body/)) {
18900 node.className = '';
18911 this.cleanUpChildren(node);
18916 * Clean up MS wordisms...
18918 cleanWord : function(node)
18921 var cleanWordChildren = function()
18923 if (!node.childNodes.length) {
18926 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18927 _t.cleanWord(node.childNodes[i]);
18933 this.cleanWord(this.doc.body);
18936 if (node.nodeName == "#text") {
18937 // clean up silly Windows -- stuff?
18940 if (node.nodeName == "#comment") {
18941 node.parentNode.removeChild(node);
18942 // clean up silly Windows -- stuff?
18946 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18947 node.parentNode.removeChild(node);
18951 // remove - but keep children..
18952 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18953 while (node.childNodes.length) {
18954 var cn = node.childNodes[0];
18955 node.removeChild(cn);
18956 node.parentNode.insertBefore(cn, node);
18958 node.parentNode.removeChild(node);
18959 cleanWordChildren();
18963 if (node.className.length) {
18965 var cn = node.className.split(/\W+/);
18967 Roo.each(cn, function(cls) {
18968 if (cls.match(/Mso[a-zA-Z]+/)) {
18973 node.className = cna.length ? cna.join(' ') : '';
18975 node.removeAttribute("class");
18979 if (node.hasAttribute("lang")) {
18980 node.removeAttribute("lang");
18983 if (node.hasAttribute("style")) {
18985 var styles = node.getAttribute("style").split(";");
18987 Roo.each(styles, function(s) {
18988 if (!s.match(/:/)) {
18991 var kv = s.split(":");
18992 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18995 // what ever is left... we allow.
18998 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18999 if (!nstyle.length) {
19000 node.removeAttribute('style');
19004 cleanWordChildren();
19008 domToHTML : function(currentElement, depth, nopadtext) {
19010 depth = depth || 0;
19011 nopadtext = nopadtext || false;
19013 if (!currentElement) {
19014 return this.domToHTML(this.doc.body);
19017 //Roo.log(currentElement);
19019 var allText = false;
19020 var nodeName = currentElement.nodeName;
19021 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19023 if (nodeName == '#text') {
19025 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19030 if (nodeName != 'BODY') {
19033 // Prints the node tagName, such as <A>, <IMG>, etc
19036 for(i = 0; i < currentElement.attributes.length;i++) {
19038 var aname = currentElement.attributes.item(i).name;
19039 if (!currentElement.attributes.item(i).value.length) {
19042 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19045 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19054 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19057 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19062 // Traverse the tree
19064 var currentElementChild = currentElement.childNodes.item(i);
19065 var allText = true;
19066 var innerHTML = '';
19068 while (currentElementChild) {
19069 // Formatting code (indent the tree so it looks nice on the screen)
19070 var nopad = nopadtext;
19071 if (lastnode == 'SPAN') {
19075 if (currentElementChild.nodeName == '#text') {
19076 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19077 toadd = nopadtext ? toadd : toadd.trim();
19078 if (!nopad && toadd.length > 80) {
19079 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19081 innerHTML += toadd;
19084 currentElementChild = currentElement.childNodes.item(i);
19090 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19092 // Recursively traverse the tree structure of the child node
19093 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19094 lastnode = currentElementChild.nodeName;
19096 currentElementChild=currentElement.childNodes.item(i);
19102 // The remaining code is mostly for formatting the tree
19103 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19108 ret+= "</"+tagName+">";
19114 applyBlacklists : function()
19116 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19117 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19121 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19122 if (b.indexOf(tag) > -1) {
19125 this.white.push(tag);
19129 Roo.each(w, function(tag) {
19130 if (b.indexOf(tag) > -1) {
19133 if (this.white.indexOf(tag) > -1) {
19136 this.white.push(tag);
19141 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19142 if (w.indexOf(tag) > -1) {
19145 this.black.push(tag);
19149 Roo.each(b, function(tag) {
19150 if (w.indexOf(tag) > -1) {
19153 if (this.black.indexOf(tag) > -1) {
19156 this.black.push(tag);
19161 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19162 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19166 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19167 if (b.indexOf(tag) > -1) {
19170 this.cwhite.push(tag);
19174 Roo.each(w, function(tag) {
19175 if (b.indexOf(tag) > -1) {
19178 if (this.cwhite.indexOf(tag) > -1) {
19181 this.cwhite.push(tag);
19186 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19187 if (w.indexOf(tag) > -1) {
19190 this.cblack.push(tag);
19194 Roo.each(b, function(tag) {
19195 if (w.indexOf(tag) > -1) {
19198 if (this.cblack.indexOf(tag) > -1) {
19201 this.cblack.push(tag);
19206 setStylesheets : function(stylesheets)
19208 if(typeof(stylesheets) == 'string'){
19209 Roo.get(this.iframe.contentDocument.head).createChild({
19211 rel : 'stylesheet',
19220 Roo.each(stylesheets, function(s) {
19225 Roo.get(_this.iframe.contentDocument.head).createChild({
19227 rel : 'stylesheet',
19236 removeStylesheets : function()
19240 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19245 // hide stuff that is not compatible
19259 * @event specialkey
19263 * @cfg {String} fieldClass @hide
19266 * @cfg {String} focusClass @hide
19269 * @cfg {String} autoCreate @hide
19272 * @cfg {String} inputType @hide
19275 * @cfg {String} invalidClass @hide
19278 * @cfg {String} invalidText @hide
19281 * @cfg {String} msgFx @hide
19284 * @cfg {String} validateOnBlur @hide
19288 Roo.HtmlEditorCore.white = [
19289 'area', 'br', 'img', 'input', 'hr', 'wbr',
19291 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19292 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19293 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19294 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19295 'table', 'ul', 'xmp',
19297 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19300 'dir', 'menu', 'ol', 'ul', 'dl',
19306 Roo.HtmlEditorCore.black = [
19307 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19309 'base', 'basefont', 'bgsound', 'blink', 'body',
19310 'frame', 'frameset', 'head', 'html', 'ilayer',
19311 'iframe', 'layer', 'link', 'meta', 'object',
19312 'script', 'style' ,'title', 'xml' // clean later..
19314 Roo.HtmlEditorCore.clean = [
19315 'script', 'style', 'title', 'xml'
19317 Roo.HtmlEditorCore.remove = [
19322 Roo.HtmlEditorCore.ablack = [
19326 Roo.HtmlEditorCore.aclean = [
19327 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19331 Roo.HtmlEditorCore.pwhite= [
19332 'http', 'https', 'mailto'
19335 // white listed style attributes.
19336 Roo.HtmlEditorCore.cwhite= [
19337 // 'text-align', /// default is to allow most things..
19343 // black listed style attributes.
19344 Roo.HtmlEditorCore.cblack= [
19345 // 'font-size' -- this can be set by the project
19349 Roo.HtmlEditorCore.swapCodes =[
19368 * @class Roo.bootstrap.HtmlEditor
19369 * @extends Roo.bootstrap.TextArea
19370 * Bootstrap HtmlEditor class
19373 * Create a new HtmlEditor
19374 * @param {Object} config The config object
19377 Roo.bootstrap.HtmlEditor = function(config){
19378 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19379 if (!this.toolbars) {
19380 this.toolbars = [];
19382 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19385 * @event initialize
19386 * Fires when the editor is fully initialized (including the iframe)
19387 * @param {HtmlEditor} this
19392 * Fires when the editor is first receives the focus. Any insertion must wait
19393 * until after this event.
19394 * @param {HtmlEditor} this
19398 * @event beforesync
19399 * Fires before the textarea is updated with content from the editor iframe. Return false
19400 * to cancel the sync.
19401 * @param {HtmlEditor} this
19402 * @param {String} html
19406 * @event beforepush
19407 * Fires before the iframe editor is updated with content from the textarea. Return false
19408 * to cancel the push.
19409 * @param {HtmlEditor} this
19410 * @param {String} html
19415 * Fires when the textarea is updated with content from the editor iframe.
19416 * @param {HtmlEditor} this
19417 * @param {String} html
19422 * Fires when the iframe editor is updated with content from the textarea.
19423 * @param {HtmlEditor} this
19424 * @param {String} html
19428 * @event editmodechange
19429 * Fires when the editor switches edit modes
19430 * @param {HtmlEditor} this
19431 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19433 editmodechange: true,
19435 * @event editorevent
19436 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19437 * @param {HtmlEditor} this
19441 * @event firstfocus
19442 * Fires when on first focus - needed by toolbars..
19443 * @param {HtmlEditor} this
19448 * Auto save the htmlEditor value as a file into Events
19449 * @param {HtmlEditor} this
19453 * @event savedpreview
19454 * preview the saved version of htmlEditor
19455 * @param {HtmlEditor} this
19462 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19466 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19471 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19476 * @cfg {Number} height (in pixels)
19480 * @cfg {Number} width (in pixels)
19485 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19488 stylesheets: false,
19493 // private properties
19494 validationEvent : false,
19496 initialized : false,
19499 onFocus : Roo.emptyFn,
19501 hideMode:'offsets',
19504 tbContainer : false,
19506 toolbarContainer :function() {
19507 return this.wrap.select('.x-html-editor-tb',true).first();
19511 * Protected method that will not generally be called directly. It
19512 * is called when the editor creates its toolbar. Override this method if you need to
19513 * add custom toolbar buttons.
19514 * @param {HtmlEditor} editor
19516 createToolbar : function(){
19518 Roo.log("create toolbars");
19520 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19521 this.toolbars[0].render(this.toolbarContainer());
19525 // if (!editor.toolbars || !editor.toolbars.length) {
19526 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19529 // for (var i =0 ; i < editor.toolbars.length;i++) {
19530 // editor.toolbars[i] = Roo.factory(
19531 // typeof(editor.toolbars[i]) == 'string' ?
19532 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19533 // Roo.bootstrap.HtmlEditor);
19534 // editor.toolbars[i].init(editor);
19540 onRender : function(ct, position)
19542 // Roo.log("Call onRender: " + this.xtype);
19544 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19546 this.wrap = this.inputEl().wrap({
19547 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19550 this.editorcore.onRender(ct, position);
19552 if (this.resizable) {
19553 this.resizeEl = new Roo.Resizable(this.wrap, {
19557 minHeight : this.height,
19558 height: this.height,
19559 handles : this.resizable,
19562 resize : function(r, w, h) {
19563 _t.onResize(w,h); // -something
19569 this.createToolbar(this);
19572 if(!this.width && this.resizable){
19573 this.setSize(this.wrap.getSize());
19575 if (this.resizeEl) {
19576 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19577 // should trigger onReize..
19583 onResize : function(w, h)
19585 Roo.log('resize: ' +w + ',' + h );
19586 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19590 if(this.inputEl() ){
19591 if(typeof w == 'number'){
19592 var aw = w - this.wrap.getFrameWidth('lr');
19593 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19596 if(typeof h == 'number'){
19597 var tbh = -11; // fixme it needs to tool bar size!
19598 for (var i =0; i < this.toolbars.length;i++) {
19599 // fixme - ask toolbars for heights?
19600 tbh += this.toolbars[i].el.getHeight();
19601 //if (this.toolbars[i].footer) {
19602 // tbh += this.toolbars[i].footer.el.getHeight();
19610 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19611 ah -= 5; // knock a few pixes off for look..
19612 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19616 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19617 this.editorcore.onResize(ew,eh);
19622 * Toggles the editor between standard and source edit mode.
19623 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19625 toggleSourceEdit : function(sourceEditMode)
19627 this.editorcore.toggleSourceEdit(sourceEditMode);
19629 if(this.editorcore.sourceEditMode){
19630 Roo.log('editor - showing textarea');
19633 // Roo.log(this.syncValue());
19635 this.inputEl().removeClass(['hide', 'x-hidden']);
19636 this.inputEl().dom.removeAttribute('tabIndex');
19637 this.inputEl().focus();
19639 Roo.log('editor - hiding textarea');
19641 // Roo.log(this.pushValue());
19644 this.inputEl().addClass(['hide', 'x-hidden']);
19645 this.inputEl().dom.setAttribute('tabIndex', -1);
19646 //this.deferFocus();
19649 if(this.resizable){
19650 this.setSize(this.wrap.getSize());
19653 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19656 // private (for BoxComponent)
19657 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19659 // private (for BoxComponent)
19660 getResizeEl : function(){
19664 // private (for BoxComponent)
19665 getPositionEl : function(){
19670 initEvents : function(){
19671 this.originalValue = this.getValue();
19675 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19678 // markInvalid : Roo.emptyFn,
19680 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19683 // clearInvalid : Roo.emptyFn,
19685 setValue : function(v){
19686 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19687 this.editorcore.pushValue();
19692 deferFocus : function(){
19693 this.focus.defer(10, this);
19697 focus : function(){
19698 this.editorcore.focus();
19704 onDestroy : function(){
19710 for (var i =0; i < this.toolbars.length;i++) {
19711 // fixme - ask toolbars for heights?
19712 this.toolbars[i].onDestroy();
19715 this.wrap.dom.innerHTML = '';
19716 this.wrap.remove();
19721 onFirstFocus : function(){
19722 //Roo.log("onFirstFocus");
19723 this.editorcore.onFirstFocus();
19724 for (var i =0; i < this.toolbars.length;i++) {
19725 this.toolbars[i].onFirstFocus();
19731 syncValue : function()
19733 this.editorcore.syncValue();
19736 pushValue : function()
19738 this.editorcore.pushValue();
19742 // hide stuff that is not compatible
19756 * @event specialkey
19760 * @cfg {String} fieldClass @hide
19763 * @cfg {String} focusClass @hide
19766 * @cfg {String} autoCreate @hide
19769 * @cfg {String} inputType @hide
19772 * @cfg {String} invalidClass @hide
19775 * @cfg {String} invalidText @hide
19778 * @cfg {String} msgFx @hide
19781 * @cfg {String} validateOnBlur @hide
19790 Roo.namespace('Roo.bootstrap.htmleditor');
19792 * @class Roo.bootstrap.HtmlEditorToolbar1
19797 new Roo.bootstrap.HtmlEditor({
19800 new Roo.bootstrap.HtmlEditorToolbar1({
19801 disable : { fonts: 1 , format: 1, ..., ... , ...],
19807 * @cfg {Object} disable List of elements to disable..
19808 * @cfg {Array} btns List of additional buttons.
19812 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19815 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19818 Roo.apply(this, config);
19820 // default disabled, based on 'good practice'..
19821 this.disable = this.disable || {};
19822 Roo.applyIf(this.disable, {
19825 specialElements : true
19827 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19829 this.editor = config.editor;
19830 this.editorcore = config.editor.editorcore;
19832 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19834 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19835 // dont call parent... till later.
19837 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19842 editorcore : false,
19847 "h1","h2","h3","h4","h5","h6",
19849 "abbr", "acronym", "address", "cite", "samp", "var",
19853 onRender : function(ct, position)
19855 // Roo.log("Call onRender: " + this.xtype);
19857 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19859 this.el.dom.style.marginBottom = '0';
19861 var editorcore = this.editorcore;
19862 var editor= this.editor;
19865 var btn = function(id,cmd , toggle, handler){
19867 var event = toggle ? 'toggle' : 'click';
19872 xns: Roo.bootstrap,
19875 enableToggle:toggle !== false,
19877 pressed : toggle ? false : null,
19880 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19881 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19890 xns: Roo.bootstrap,
19891 glyphicon : 'font',
19895 xns: Roo.bootstrap,
19899 Roo.each(this.formats, function(f) {
19900 style.menu.items.push({
19902 xns: Roo.bootstrap,
19903 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19908 editorcore.insertTag(this.tagname);
19915 children.push(style);
19918 btn('bold',false,true);
19919 btn('italic',false,true);
19920 btn('align-left', 'justifyleft',true);
19921 btn('align-center', 'justifycenter',true);
19922 btn('align-right' , 'justifyright',true);
19923 btn('link', false, false, function(btn) {
19924 //Roo.log("create link?");
19925 var url = prompt(this.createLinkText, this.defaultLinkValue);
19926 if(url && url != 'http:/'+'/'){
19927 this.editorcore.relayCmd('createlink', url);
19930 btn('list','insertunorderedlist',true);
19931 btn('pencil', false,true, function(btn){
19934 this.toggleSourceEdit(btn.pressed);
19940 xns: Roo.bootstrap,
19945 xns: Roo.bootstrap,
19950 cog.menu.items.push({
19952 xns: Roo.bootstrap,
19953 html : Clean styles,
19958 editorcore.insertTag(this.tagname);
19967 this.xtype = 'NavSimplebar';
19969 for(var i=0;i< children.length;i++) {
19971 this.buttons.add(this.addxtypeChild(children[i]));
19975 editor.on('editorevent', this.updateToolbar, this);
19977 onBtnClick : function(id)
19979 this.editorcore.relayCmd(id);
19980 this.editorcore.focus();
19984 * Protected method that will not generally be called directly. It triggers
19985 * a toolbar update by reading the markup state of the current selection in the editor.
19987 updateToolbar: function(){
19989 if(!this.editorcore.activated){
19990 this.editor.onFirstFocus(); // is this neeed?
19994 var btns = this.buttons;
19995 var doc = this.editorcore.doc;
19996 btns.get('bold').setActive(doc.queryCommandState('bold'));
19997 btns.get('italic').setActive(doc.queryCommandState('italic'));
19998 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20000 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20001 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20002 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20004 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20005 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20008 var ans = this.editorcore.getAllAncestors();
20009 if (this.formatCombo) {
20012 var store = this.formatCombo.store;
20013 this.formatCombo.setValue("");
20014 for (var i =0; i < ans.length;i++) {
20015 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20017 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20025 // hides menus... - so this cant be on a menu...
20026 Roo.bootstrap.MenuMgr.hideAll();
20028 Roo.bootstrap.MenuMgr.hideAll();
20029 //this.editorsyncValue();
20031 onFirstFocus: function() {
20032 this.buttons.each(function(item){
20036 toggleSourceEdit : function(sourceEditMode){
20039 if(sourceEditMode){
20040 Roo.log("disabling buttons");
20041 this.buttons.each( function(item){
20042 if(item.cmd != 'pencil'){
20048 Roo.log("enabling buttons");
20049 if(this.editorcore.initialized){
20050 this.buttons.each( function(item){
20056 Roo.log("calling toggole on editor");
20057 // tell the editor that it's been pressed..
20058 this.editor.toggleSourceEdit(sourceEditMode);
20068 * @class Roo.bootstrap.Table.AbstractSelectionModel
20069 * @extends Roo.util.Observable
20070 * Abstract base class for grid SelectionModels. It provides the interface that should be
20071 * implemented by descendant classes. This class should not be directly instantiated.
20074 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20075 this.locked = false;
20076 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20080 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20081 /** @ignore Called by the grid automatically. Do not call directly. */
20082 init : function(grid){
20088 * Locks the selections.
20091 this.locked = true;
20095 * Unlocks the selections.
20097 unlock : function(){
20098 this.locked = false;
20102 * Returns true if the selections are locked.
20103 * @return {Boolean}
20105 isLocked : function(){
20106 return this.locked;
20110 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20111 * @class Roo.bootstrap.Table.RowSelectionModel
20112 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20113 * It supports multiple selections and keyboard selection/navigation.
20115 * @param {Object} config
20118 Roo.bootstrap.Table.RowSelectionModel = function(config){
20119 Roo.apply(this, config);
20120 this.selections = new Roo.util.MixedCollection(false, function(o){
20125 this.lastActive = false;
20129 * @event selectionchange
20130 * Fires when the selection changes
20131 * @param {SelectionModel} this
20133 "selectionchange" : true,
20135 * @event afterselectionchange
20136 * Fires after the selection changes (eg. by key press or clicking)
20137 * @param {SelectionModel} this
20139 "afterselectionchange" : true,
20141 * @event beforerowselect
20142 * Fires when a row is selected being selected, return false to cancel.
20143 * @param {SelectionModel} this
20144 * @param {Number} rowIndex The selected index
20145 * @param {Boolean} keepExisting False if other selections will be cleared
20147 "beforerowselect" : true,
20150 * Fires when a row is selected.
20151 * @param {SelectionModel} this
20152 * @param {Number} rowIndex The selected index
20153 * @param {Roo.data.Record} r The record
20155 "rowselect" : true,
20157 * @event rowdeselect
20158 * Fires when a row is deselected.
20159 * @param {SelectionModel} this
20160 * @param {Number} rowIndex The selected index
20162 "rowdeselect" : true
20164 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20165 this.locked = false;
20168 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20170 * @cfg {Boolean} singleSelect
20171 * True to allow selection of only one row at a time (defaults to false)
20173 singleSelect : false,
20176 initEvents : function(){
20178 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20179 this.grid.on("mousedown", this.handleMouseDown, this);
20180 }else{ // allow click to work like normal
20181 this.grid.on("rowclick", this.handleDragableRowClick, this);
20184 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20185 "up" : function(e){
20187 this.selectPrevious(e.shiftKey);
20188 }else if(this.last !== false && this.lastActive !== false){
20189 var last = this.last;
20190 this.selectRange(this.last, this.lastActive-1);
20191 this.grid.getView().focusRow(this.lastActive);
20192 if(last !== false){
20196 this.selectFirstRow();
20198 this.fireEvent("afterselectionchange", this);
20200 "down" : function(e){
20202 this.selectNext(e.shiftKey);
20203 }else if(this.last !== false && this.lastActive !== false){
20204 var last = this.last;
20205 this.selectRange(this.last, this.lastActive+1);
20206 this.grid.getView().focusRow(this.lastActive);
20207 if(last !== false){
20211 this.selectFirstRow();
20213 this.fireEvent("afterselectionchange", this);
20218 var view = this.grid.view;
20219 view.on("refresh", this.onRefresh, this);
20220 view.on("rowupdated", this.onRowUpdated, this);
20221 view.on("rowremoved", this.onRemove, this);
20225 onRefresh : function(){
20226 var ds = this.grid.dataSource, i, v = this.grid.view;
20227 var s = this.selections;
20228 s.each(function(r){
20229 if((i = ds.indexOfId(r.id)) != -1){
20238 onRemove : function(v, index, r){
20239 this.selections.remove(r);
20243 onRowUpdated : function(v, index, r){
20244 if(this.isSelected(r)){
20245 v.onRowSelect(index);
20251 * @param {Array} records The records to select
20252 * @param {Boolean} keepExisting (optional) True to keep existing selections
20254 selectRecords : function(records, keepExisting){
20256 this.clearSelections();
20258 var ds = this.grid.dataSource;
20259 for(var i = 0, len = records.length; i < len; i++){
20260 this.selectRow(ds.indexOf(records[i]), true);
20265 * Gets the number of selected rows.
20268 getCount : function(){
20269 return this.selections.length;
20273 * Selects the first row in the grid.
20275 selectFirstRow : function(){
20280 * Select the last row.
20281 * @param {Boolean} keepExisting (optional) True to keep existing selections
20283 selectLastRow : function(keepExisting){
20284 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20288 * Selects the row immediately following the last selected row.
20289 * @param {Boolean} keepExisting (optional) True to keep existing selections
20291 selectNext : function(keepExisting){
20292 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20293 this.selectRow(this.last+1, keepExisting);
20294 this.grid.getView().focusRow(this.last);
20299 * Selects the row that precedes the last selected row.
20300 * @param {Boolean} keepExisting (optional) True to keep existing selections
20302 selectPrevious : function(keepExisting){
20304 this.selectRow(this.last-1, keepExisting);
20305 this.grid.getView().focusRow(this.last);
20310 * Returns the selected records
20311 * @return {Array} Array of selected records
20313 getSelections : function(){
20314 return [].concat(this.selections.items);
20318 * Returns the first selected record.
20321 getSelected : function(){
20322 return this.selections.itemAt(0);
20327 * Clears all selections.
20329 clearSelections : function(fast){
20330 if(this.locked) return;
20332 var ds = this.grid.dataSource;
20333 var s = this.selections;
20334 s.each(function(r){
20335 this.deselectRow(ds.indexOfId(r.id));
20339 this.selections.clear();
20346 * Selects all rows.
20348 selectAll : function(){
20349 if(this.locked) return;
20350 this.selections.clear();
20351 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20352 this.selectRow(i, true);
20357 * Returns True if there is a selection.
20358 * @return {Boolean}
20360 hasSelection : function(){
20361 return this.selections.length > 0;
20365 * Returns True if the specified row is selected.
20366 * @param {Number/Record} record The record or index of the record to check
20367 * @return {Boolean}
20369 isSelected : function(index){
20370 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20371 return (r && this.selections.key(r.id) ? true : false);
20375 * Returns True if the specified record id is selected.
20376 * @param {String} id The id of record to check
20377 * @return {Boolean}
20379 isIdSelected : function(id){
20380 return (this.selections.key(id) ? true : false);
20384 handleMouseDown : function(e, t){
20385 var view = this.grid.getView(), rowIndex;
20386 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20389 if(e.shiftKey && this.last !== false){
20390 var last = this.last;
20391 this.selectRange(last, rowIndex, e.ctrlKey);
20392 this.last = last; // reset the last
20393 view.focusRow(rowIndex);
20395 var isSelected = this.isSelected(rowIndex);
20396 if(e.button !== 0 && isSelected){
20397 view.focusRow(rowIndex);
20398 }else if(e.ctrlKey && isSelected){
20399 this.deselectRow(rowIndex);
20400 }else if(!isSelected){
20401 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20402 view.focusRow(rowIndex);
20405 this.fireEvent("afterselectionchange", this);
20408 handleDragableRowClick : function(grid, rowIndex, e)
20410 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20411 this.selectRow(rowIndex, false);
20412 grid.view.focusRow(rowIndex);
20413 this.fireEvent("afterselectionchange", this);
20418 * Selects multiple rows.
20419 * @param {Array} rows Array of the indexes of the row to select
20420 * @param {Boolean} keepExisting (optional) True to keep existing selections
20422 selectRows : function(rows, keepExisting){
20424 this.clearSelections();
20426 for(var i = 0, len = rows.length; i < len; i++){
20427 this.selectRow(rows[i], true);
20432 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20433 * @param {Number} startRow The index of the first row in the range
20434 * @param {Number} endRow The index of the last row in the range
20435 * @param {Boolean} keepExisting (optional) True to retain existing selections
20437 selectRange : function(startRow, endRow, keepExisting){
20438 if(this.locked) return;
20440 this.clearSelections();
20442 if(startRow <= endRow){
20443 for(var i = startRow; i <= endRow; i++){
20444 this.selectRow(i, true);
20447 for(var i = startRow; i >= endRow; i--){
20448 this.selectRow(i, true);
20454 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20455 * @param {Number} startRow The index of the first row in the range
20456 * @param {Number} endRow The index of the last row in the range
20458 deselectRange : function(startRow, endRow, preventViewNotify){
20459 if(this.locked) return;
20460 for(var i = startRow; i <= endRow; i++){
20461 this.deselectRow(i, preventViewNotify);
20467 * @param {Number} row The index of the row to select
20468 * @param {Boolean} keepExisting (optional) True to keep existing selections
20470 selectRow : function(index, keepExisting, preventViewNotify){
20471 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20472 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20473 if(!keepExisting || this.singleSelect){
20474 this.clearSelections();
20476 var r = this.grid.dataSource.getAt(index);
20477 this.selections.add(r);
20478 this.last = this.lastActive = index;
20479 if(!preventViewNotify){
20480 this.grid.getView().onRowSelect(index);
20482 this.fireEvent("rowselect", this, index, r);
20483 this.fireEvent("selectionchange", this);
20489 * @param {Number} row The index of the row to deselect
20491 deselectRow : function(index, preventViewNotify){
20492 if(this.locked) return;
20493 if(this.last == index){
20496 if(this.lastActive == index){
20497 this.lastActive = false;
20499 var r = this.grid.dataSource.getAt(index);
20500 this.selections.remove(r);
20501 if(!preventViewNotify){
20502 this.grid.getView().onRowDeselect(index);
20504 this.fireEvent("rowdeselect", this, index);
20505 this.fireEvent("selectionchange", this);
20509 restoreLast : function(){
20511 this.last = this._last;
20516 acceptsNav : function(row, col, cm){
20517 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20521 onEditorKey : function(field, e){
20522 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20527 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20529 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20531 }else if(k == e.ENTER && !e.ctrlKey){
20535 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20537 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20539 }else if(k == e.ESC){
20543 g.startEditing(newCell[0], newCell[1]);
20548 * Ext JS Library 1.1.1
20549 * Copyright(c) 2006-2007, Ext JS, LLC.
20551 * Originally Released Under LGPL - original licence link has changed is not relivant.
20554 * <script type="text/javascript">
20558 * @class Roo.bootstrap.PagingToolbar
20560 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20562 * Create a new PagingToolbar
20563 * @param {Object} config The config object
20565 Roo.bootstrap.PagingToolbar = function(config)
20567 // old args format still supported... - xtype is prefered..
20568 // created from xtype...
20569 var ds = config.dataSource;
20570 this.toolbarItems = [];
20571 if (config.items) {
20572 this.toolbarItems = config.items;
20573 // config.items = [];
20576 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20583 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20587 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20589 * @cfg {Roo.data.Store} dataSource
20590 * The underlying data store providing the paged data
20593 * @cfg {String/HTMLElement/Element} container
20594 * container The id or element that will contain the toolbar
20597 * @cfg {Boolean} displayInfo
20598 * True to display the displayMsg (defaults to false)
20601 * @cfg {Number} pageSize
20602 * The number of records to display per page (defaults to 20)
20606 * @cfg {String} displayMsg
20607 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20609 displayMsg : 'Displaying {0} - {1} of {2}',
20611 * @cfg {String} emptyMsg
20612 * The message to display when no records are found (defaults to "No data to display")
20614 emptyMsg : 'No data to display',
20616 * Customizable piece of the default paging text (defaults to "Page")
20619 beforePageText : "Page",
20621 * Customizable piece of the default paging text (defaults to "of %0")
20624 afterPageText : "of {0}",
20626 * Customizable piece of the default paging text (defaults to "First Page")
20629 firstText : "First Page",
20631 * Customizable piece of the default paging text (defaults to "Previous Page")
20634 prevText : "Previous Page",
20636 * Customizable piece of the default paging text (defaults to "Next Page")
20639 nextText : "Next Page",
20641 * Customizable piece of the default paging text (defaults to "Last Page")
20644 lastText : "Last Page",
20646 * Customizable piece of the default paging text (defaults to "Refresh")
20649 refreshText : "Refresh",
20653 onRender : function(ct, position)
20655 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20656 this.navgroup.parentId = this.id;
20657 this.navgroup.onRender(this.el, null);
20658 // add the buttons to the navgroup
20660 if(this.displayInfo){
20661 Roo.log(this.el.select('ul.navbar-nav',true).first());
20662 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20663 this.displayEl = this.el.select('.x-paging-info', true).first();
20664 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20665 // this.displayEl = navel.el.select('span',true).first();
20671 Roo.each(_this.buttons, function(e){
20672 Roo.factory(e).onRender(_this.el, null);
20676 Roo.each(_this.toolbarItems, function(e) {
20677 _this.navgroup.addItem(e);
20681 this.first = this.navgroup.addItem({
20682 tooltip: this.firstText,
20684 icon : 'fa fa-backward',
20686 preventDefault: true,
20687 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20690 this.prev = this.navgroup.addItem({
20691 tooltip: this.prevText,
20693 icon : 'fa fa-step-backward',
20695 preventDefault: true,
20696 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20698 //this.addSeparator();
20701 var field = this.navgroup.addItem( {
20703 cls : 'x-paging-position',
20705 html : this.beforePageText +
20706 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20707 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20710 this.field = field.el.select('input', true).first();
20711 this.field.on("keydown", this.onPagingKeydown, this);
20712 this.field.on("focus", function(){this.dom.select();});
20715 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20716 //this.field.setHeight(18);
20717 //this.addSeparator();
20718 this.next = this.navgroup.addItem({
20719 tooltip: this.nextText,
20721 html : ' <i class="fa fa-step-forward">',
20723 preventDefault: true,
20724 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20726 this.last = this.navgroup.addItem({
20727 tooltip: this.lastText,
20728 icon : 'fa fa-forward',
20731 preventDefault: true,
20732 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20734 //this.addSeparator();
20735 this.loading = this.navgroup.addItem({
20736 tooltip: this.refreshText,
20737 icon: 'fa fa-refresh',
20738 preventDefault: true,
20739 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20745 updateInfo : function(){
20746 if(this.displayEl){
20747 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20748 var msg = count == 0 ?
20752 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20754 this.displayEl.update(msg);
20759 onLoad : function(ds, r, o){
20760 this.cursor = o.params ? o.params.start : 0;
20761 var d = this.getPageData(),
20765 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20766 this.field.dom.value = ap;
20767 this.first.setDisabled(ap == 1);
20768 this.prev.setDisabled(ap == 1);
20769 this.next.setDisabled(ap == ps);
20770 this.last.setDisabled(ap == ps);
20771 this.loading.enable();
20776 getPageData : function(){
20777 var total = this.ds.getTotalCount();
20780 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20781 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20786 onLoadError : function(){
20787 this.loading.enable();
20791 onPagingKeydown : function(e){
20792 var k = e.getKey();
20793 var d = this.getPageData();
20795 var v = this.field.dom.value, pageNum;
20796 if(!v || isNaN(pageNum = parseInt(v, 10))){
20797 this.field.dom.value = d.activePage;
20800 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20801 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20804 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))
20806 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20807 this.field.dom.value = pageNum;
20808 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20811 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20813 var v = this.field.dom.value, pageNum;
20814 var increment = (e.shiftKey) ? 10 : 1;
20815 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20817 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20818 this.field.dom.value = d.activePage;
20821 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20823 this.field.dom.value = parseInt(v, 10) + increment;
20824 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20825 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20832 beforeLoad : function(){
20834 this.loading.disable();
20839 onClick : function(which){
20848 ds.load({params:{start: 0, limit: this.pageSize}});
20851 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20854 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20857 var total = ds.getTotalCount();
20858 var extra = total % this.pageSize;
20859 var lastStart = extra ? (total - extra) : total-this.pageSize;
20860 ds.load({params:{start: lastStart, limit: this.pageSize}});
20863 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20869 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20870 * @param {Roo.data.Store} store The data store to unbind
20872 unbind : function(ds){
20873 ds.un("beforeload", this.beforeLoad, this);
20874 ds.un("load", this.onLoad, this);
20875 ds.un("loadexception", this.onLoadError, this);
20876 ds.un("remove", this.updateInfo, this);
20877 ds.un("add", this.updateInfo, this);
20878 this.ds = undefined;
20882 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20883 * @param {Roo.data.Store} store The data store to bind
20885 bind : function(ds){
20886 ds.on("beforeload", this.beforeLoad, this);
20887 ds.on("load", this.onLoad, this);
20888 ds.on("loadexception", this.onLoadError, this);
20889 ds.on("remove", this.updateInfo, this);
20890 ds.on("add", this.updateInfo, this);
20901 * @class Roo.bootstrap.MessageBar
20902 * @extends Roo.bootstrap.Component
20903 * Bootstrap MessageBar class
20904 * @cfg {String} html contents of the MessageBar
20905 * @cfg {String} weight (info | success | warning | danger) default info
20906 * @cfg {String} beforeClass insert the bar before the given class
20907 * @cfg {Boolean} closable (true | false) default false
20908 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20911 * Create a new Element
20912 * @param {Object} config The config object
20915 Roo.bootstrap.MessageBar = function(config){
20916 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20919 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20925 beforeClass: 'bootstrap-sticky-wrap',
20927 getAutoCreate : function(){
20931 cls: 'alert alert-dismissable alert-' + this.weight,
20936 html: this.html || ''
20942 cfg.cls += ' alert-messages-fixed';
20956 onRender : function(ct, position)
20958 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20961 var cfg = Roo.apply({}, this.getAutoCreate());
20965 cfg.cls += ' ' + this.cls;
20968 cfg.style = this.style;
20970 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20972 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20975 this.el.select('>button.close').on('click', this.hide, this);
20981 if (!this.rendered) {
20987 this.fireEvent('show', this);
20993 if (!this.rendered) {
20999 this.fireEvent('hide', this);
21002 update : function()
21004 // var e = this.el.dom.firstChild;
21006 // if(this.closable){
21007 // e = e.nextSibling;
21010 // e.data = this.html || '';
21012 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21028 * @class Roo.bootstrap.Graph
21029 * @extends Roo.bootstrap.Component
21030 * Bootstrap Graph class
21034 @cfg {String} graphtype bar | vbar | pie
21035 @cfg {number} g_x coodinator | centre x (pie)
21036 @cfg {number} g_y coodinator | centre y (pie)
21037 @cfg {number} g_r radius (pie)
21038 @cfg {number} g_height height of the chart (respected by all elements in the set)
21039 @cfg {number} g_width width of the chart (respected by all elements in the set)
21040 @cfg {Object} title The title of the chart
21043 -opts (object) options for the chart
21045 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21046 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21048 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.
21049 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21051 o stretch (boolean)
21053 -opts (object) options for the pie
21056 o startAngle (number)
21057 o endAngle (number)
21061 * Create a new Input
21062 * @param {Object} config The config object
21065 Roo.bootstrap.Graph = function(config){
21066 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21072 * The img click event for the img.
21073 * @param {Roo.EventObject} e
21079 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21090 //g_colors: this.colors,
21097 getAutoCreate : function(){
21108 onRender : function(ct,position){
21109 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21110 this.raphael = Raphael(this.el.dom);
21112 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21113 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21114 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21115 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21117 r.text(160, 10, "Single Series Chart").attr(txtattr);
21118 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21119 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21120 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21122 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21123 r.barchart(330, 10, 300, 220, data1);
21124 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21125 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21128 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21129 // r.barchart(30, 30, 560, 250, xdata, {
21130 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21131 // axis : "0 0 1 1",
21132 // axisxlabels : xdata
21133 // //yvalues : cols,
21136 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21138 // this.load(null,xdata,{
21139 // axis : "0 0 1 1",
21140 // axisxlabels : xdata
21145 load : function(graphtype,xdata,opts){
21146 this.raphael.clear();
21148 graphtype = this.graphtype;
21153 var r = this.raphael,
21154 fin = function () {
21155 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21157 fout = function () {
21158 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21160 pfin = function() {
21161 this.sector.stop();
21162 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21165 this.label[0].stop();
21166 this.label[0].attr({ r: 7.5 });
21167 this.label[1].attr({ "font-weight": 800 });
21170 pfout = function() {
21171 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21174 this.label[0].animate({ r: 5 }, 500, "bounce");
21175 this.label[1].attr({ "font-weight": 400 });
21181 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21184 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21187 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21188 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21190 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21197 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21202 setTitle: function(o)
21207 initEvents: function() {
21210 this.el.on('click', this.onClick, this);
21214 onClick : function(e)
21216 Roo.log('img onclick');
21217 this.fireEvent('click', this, e);
21229 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21232 * @class Roo.bootstrap.dash.NumberBox
21233 * @extends Roo.bootstrap.Component
21234 * Bootstrap NumberBox class
21235 * @cfg {String} headline Box headline
21236 * @cfg {String} content Box content
21237 * @cfg {String} icon Box icon
21238 * @cfg {String} footer Footer text
21239 * @cfg {String} fhref Footer href
21242 * Create a new NumberBox
21243 * @param {Object} config The config object
21247 Roo.bootstrap.dash.NumberBox = function(config){
21248 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21252 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21261 getAutoCreate : function(){
21265 cls : 'small-box ',
21273 cls : 'roo-headline',
21274 html : this.headline
21278 cls : 'roo-content',
21279 html : this.content
21293 cls : 'ion ' + this.icon
21302 cls : 'small-box-footer',
21303 href : this.fhref || '#',
21307 cfg.cn.push(footer);
21314 onRender : function(ct,position){
21315 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21322 setHeadline: function (value)
21324 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21327 setFooter: function (value, href)
21329 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21332 this.el.select('a.small-box-footer',true).first().attr('href', href);
21337 setContent: function (value)
21339 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21342 initEvents: function()
21356 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21359 * @class Roo.bootstrap.dash.TabBox
21360 * @extends Roo.bootstrap.Component
21361 * Bootstrap TabBox class
21362 * @cfg {String} title Title of the TabBox
21363 * @cfg {String} icon Icon of the TabBox
21364 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21365 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21368 * Create a new TabBox
21369 * @param {Object} config The config object
21373 Roo.bootstrap.dash.TabBox = function(config){
21374 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21379 * When a pane is added
21380 * @param {Roo.bootstrap.dash.TabPane} pane
21384 * @event activatepane
21385 * When a pane is activated
21386 * @param {Roo.bootstrap.dash.TabPane} pane
21388 "activatepane" : true
21396 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21401 tabScrollable : false,
21403 getChildContainer : function()
21405 return this.el.select('.tab-content', true).first();
21408 getAutoCreate : function(){
21412 cls: 'pull-left header',
21420 cls: 'fa ' + this.icon
21426 cls: 'nav nav-tabs pull-right',
21432 if(this.tabScrollable){
21439 cls: 'nav nav-tabs pull-right',
21450 cls: 'nav-tabs-custom',
21455 cls: 'tab-content no-padding',
21463 initEvents : function()
21465 //Roo.log('add add pane handler');
21466 this.on('addpane', this.onAddPane, this);
21469 * Updates the box title
21470 * @param {String} html to set the title to.
21472 setTitle : function(value)
21474 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21476 onAddPane : function(pane)
21478 this.panes.push(pane);
21479 //Roo.log('addpane');
21481 // tabs are rendere left to right..
21482 if(!this.showtabs){
21486 var ctr = this.el.select('.nav-tabs', true).first();
21489 var existing = ctr.select('.nav-tab',true);
21490 var qty = existing.getCount();;
21493 var tab = ctr.createChild({
21495 cls : 'nav-tab' + (qty ? '' : ' active'),
21503 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21506 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21508 pane.el.addClass('active');
21513 onTabClick : function(ev,un,ob,pane)
21515 //Roo.log('tab - prev default');
21516 ev.preventDefault();
21519 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21520 pane.tab.addClass('active');
21521 //Roo.log(pane.title);
21522 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21523 // technically we should have a deactivate event.. but maybe add later.
21524 // and it should not de-activate the selected tab...
21525 this.fireEvent('activatepane', pane);
21526 pane.el.addClass('active');
21527 pane.fireEvent('activate');
21532 getActivePane : function()
21535 Roo.each(this.panes, function(p) {
21536 if(p.el.hasClass('active')){
21557 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21559 * @class Roo.bootstrap.TabPane
21560 * @extends Roo.bootstrap.Component
21561 * Bootstrap TabPane class
21562 * @cfg {Boolean} active (false | true) Default false
21563 * @cfg {String} title title of panel
21567 * Create a new TabPane
21568 * @param {Object} config The config object
21571 Roo.bootstrap.dash.TabPane = function(config){
21572 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21578 * When a pane is activated
21579 * @param {Roo.bootstrap.dash.TabPane} pane
21586 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21591 // the tabBox that this is attached to.
21594 getAutoCreate : function()
21602 cfg.cls += ' active';
21607 initEvents : function()
21609 //Roo.log('trigger add pane handler');
21610 this.parent().fireEvent('addpane', this)
21614 * Updates the tab title
21615 * @param {String} html to set the title to.
21617 setTitle: function(str)
21623 this.tab.select('a', true).first().dom.innerHTML = str;
21640 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21643 * @class Roo.bootstrap.menu.Menu
21644 * @extends Roo.bootstrap.Component
21645 * Bootstrap Menu class - container for Menu
21646 * @cfg {String} html Text of the menu
21647 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21648 * @cfg {String} icon Font awesome icon
21649 * @cfg {String} pos Menu align to (top | bottom) default bottom
21653 * Create a new Menu
21654 * @param {Object} config The config object
21658 Roo.bootstrap.menu.Menu = function(config){
21659 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21663 * @event beforeshow
21664 * Fires before this menu is displayed
21665 * @param {Roo.bootstrap.menu.Menu} this
21669 * @event beforehide
21670 * Fires before this menu is hidden
21671 * @param {Roo.bootstrap.menu.Menu} this
21676 * Fires after this menu is displayed
21677 * @param {Roo.bootstrap.menu.Menu} this
21682 * Fires after this menu is hidden
21683 * @param {Roo.bootstrap.menu.Menu} this
21688 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21689 * @param {Roo.bootstrap.menu.Menu} this
21690 * @param {Roo.EventObject} e
21697 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21701 weight : 'default',
21706 getChildContainer : function() {
21707 if(this.isSubMenu){
21711 return this.el.select('ul.dropdown-menu', true).first();
21714 getAutoCreate : function()
21719 cls : 'roo-menu-text',
21727 cls : 'fa ' + this.icon
21738 cls : 'dropdown-button btn btn-' + this.weight,
21743 cls : 'dropdown-toggle btn btn-' + this.weight,
21753 cls : 'dropdown-menu'
21759 if(this.pos == 'top'){
21760 cfg.cls += ' dropup';
21763 if(this.isSubMenu){
21766 cls : 'dropdown-menu'
21773 onRender : function(ct, position)
21775 this.isSubMenu = ct.hasClass('dropdown-submenu');
21777 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21780 initEvents : function()
21782 if(this.isSubMenu){
21786 this.hidden = true;
21788 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21789 this.triggerEl.on('click', this.onTriggerPress, this);
21791 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21792 this.buttonEl.on('click', this.onClick, this);
21798 if(this.isSubMenu){
21802 return this.el.select('ul.dropdown-menu', true).first();
21805 onClick : function(e)
21807 this.fireEvent("click", this, e);
21810 onTriggerPress : function(e)
21812 if (this.isVisible()) {
21819 isVisible : function(){
21820 return !this.hidden;
21825 this.fireEvent("beforeshow", this);
21827 this.hidden = false;
21828 this.el.addClass('open');
21830 Roo.get(document).on("mouseup", this.onMouseUp, this);
21832 this.fireEvent("show", this);
21839 this.fireEvent("beforehide", this);
21841 this.hidden = true;
21842 this.el.removeClass('open');
21844 Roo.get(document).un("mouseup", this.onMouseUp);
21846 this.fireEvent("hide", this);
21849 onMouseUp : function()
21863 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21866 * @class Roo.bootstrap.menu.Item
21867 * @extends Roo.bootstrap.Component
21868 * Bootstrap MenuItem class
21869 * @cfg {Boolean} submenu (true | false) default false
21870 * @cfg {String} html text of the item
21871 * @cfg {String} href the link
21872 * @cfg {Boolean} disable (true | false) default false
21873 * @cfg {Boolean} preventDefault (true | false) default true
21874 * @cfg {String} icon Font awesome icon
21875 * @cfg {String} pos Submenu align to (left | right) default right
21879 * Create a new Item
21880 * @param {Object} config The config object
21884 Roo.bootstrap.menu.Item = function(config){
21885 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21889 * Fires when the mouse is hovering over this menu
21890 * @param {Roo.bootstrap.menu.Item} this
21891 * @param {Roo.EventObject} e
21896 * Fires when the mouse exits this menu
21897 * @param {Roo.bootstrap.menu.Item} this
21898 * @param {Roo.EventObject} e
21904 * The raw click event for the entire grid.
21905 * @param {Roo.EventObject} e
21911 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21916 preventDefault: true,
21921 getAutoCreate : function()
21926 cls : 'roo-menu-item-text',
21934 cls : 'fa ' + this.icon
21943 href : this.href || '#',
21950 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21954 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21956 if(this.pos == 'left'){
21957 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21964 initEvents : function()
21966 this.el.on('mouseover', this.onMouseOver, this);
21967 this.el.on('mouseout', this.onMouseOut, this);
21969 this.el.select('a', true).first().on('click', this.onClick, this);
21973 onClick : function(e)
21975 if(this.preventDefault){
21976 e.preventDefault();
21979 this.fireEvent("click", this, e);
21982 onMouseOver : function(e)
21984 if(this.submenu && this.pos == 'left'){
21985 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21988 this.fireEvent("mouseover", this, e);
21991 onMouseOut : function(e)
21993 this.fireEvent("mouseout", this, e);
22005 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22008 * @class Roo.bootstrap.menu.Separator
22009 * @extends Roo.bootstrap.Component
22010 * Bootstrap Separator class
22013 * Create a new Separator
22014 * @param {Object} config The config object
22018 Roo.bootstrap.menu.Separator = function(config){
22019 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22022 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22024 getAutoCreate : function(){
22045 * @class Roo.bootstrap.Tooltip
22046 * Bootstrap Tooltip class
22047 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22048 * to determine which dom element triggers the tooltip.
22050 * It needs to add support for additional attributes like tooltip-position
22053 * Create a new Toolti
22054 * @param {Object} config The config object
22057 Roo.bootstrap.Tooltip = function(config){
22058 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22061 Roo.apply(Roo.bootstrap.Tooltip, {
22063 * @function init initialize tooltip monitoring.
22067 currentTip : false,
22068 currentRegion : false,
22074 Roo.get(document).on('mouseover', this.enter ,this);
22075 Roo.get(document).on('mouseout', this.leave, this);
22078 this.currentTip = new Roo.bootstrap.Tooltip();
22081 enter : function(ev)
22083 var dom = ev.getTarget();
22085 //Roo.log(['enter',dom]);
22086 var el = Roo.fly(dom);
22087 if (this.currentEl) {
22089 //Roo.log(this.currentEl);
22090 //Roo.log(this.currentEl.contains(dom));
22091 if (this.currentEl == el) {
22094 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22102 if (this.currentTip.el) {
22103 this.currentTip.el.hide(); // force hiding...
22108 // you can not look for children, as if el is the body.. then everythign is the child..
22109 if (!el.attr('tooltip')) { //
22110 if (!el.select("[tooltip]").elements.length) {
22113 // is the mouse over this child...?
22114 bindEl = el.select("[tooltip]").first();
22115 var xy = ev.getXY();
22116 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22117 //Roo.log("not in region.");
22120 //Roo.log("child element over..");
22123 this.currentEl = bindEl;
22124 this.currentTip.bind(bindEl);
22125 this.currentRegion = Roo.lib.Region.getRegion(dom);
22126 this.currentTip.enter();
22129 leave : function(ev)
22131 var dom = ev.getTarget();
22132 //Roo.log(['leave',dom]);
22133 if (!this.currentEl) {
22138 if (dom != this.currentEl.dom) {
22141 var xy = ev.getXY();
22142 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22145 // only activate leave if mouse cursor is outside... bounding box..
22150 if (this.currentTip) {
22151 this.currentTip.leave();
22153 //Roo.log('clear currentEl');
22154 this.currentEl = false;
22159 'left' : ['r-l', [-2,0], 'right'],
22160 'right' : ['l-r', [2,0], 'left'],
22161 'bottom' : ['t-b', [0,2], 'top'],
22162 'top' : [ 'b-t', [0,-2], 'bottom']
22168 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22173 delay : null, // can be { show : 300 , hide: 500}
22177 hoverState : null, //???
22179 placement : 'bottom',
22181 getAutoCreate : function(){
22188 cls : 'tooltip-arrow'
22191 cls : 'tooltip-inner'
22198 bind : function(el)
22204 enter : function () {
22206 if (this.timeout != null) {
22207 clearTimeout(this.timeout);
22210 this.hoverState = 'in';
22211 //Roo.log("enter - show");
22212 if (!this.delay || !this.delay.show) {
22217 this.timeout = setTimeout(function () {
22218 if (_t.hoverState == 'in') {
22221 }, this.delay.show);
22225 clearTimeout(this.timeout);
22227 this.hoverState = 'out';
22228 if (!this.delay || !this.delay.hide) {
22234 this.timeout = setTimeout(function () {
22235 //Roo.log("leave - timeout");
22237 if (_t.hoverState == 'out') {
22239 Roo.bootstrap.Tooltip.currentEl = false;
22247 this.render(document.body);
22250 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22252 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22254 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22256 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22258 var placement = typeof this.placement == 'function' ?
22259 this.placement.call(this, this.el, on_el) :
22262 var autoToken = /\s?auto?\s?/i;
22263 var autoPlace = autoToken.test(placement);
22265 placement = placement.replace(autoToken, '') || 'top';
22269 //this.el.setXY([0,0]);
22271 //this.el.dom.style.display='block';
22272 this.el.addClass(placement);
22274 //this.el.appendTo(on_el);
22276 var p = this.getPosition();
22277 var box = this.el.getBox();
22282 var align = Roo.bootstrap.Tooltip.alignment[placement];
22283 this.el.alignTo(this.bindEl, align[0],align[1]);
22284 //var arrow = this.el.select('.arrow',true).first();
22285 //arrow.set(align[2],
22287 this.el.addClass('in fade');
22288 this.hoverState = null;
22290 if (this.el.hasClass('fade')) {
22301 //this.el.setXY([0,0]);
22302 this.el.removeClass('in');
22318 * @class Roo.bootstrap.LocationPicker
22319 * @extends Roo.bootstrap.Component
22320 * Bootstrap LocationPicker class
22321 * @cfg {Number} latitude Position when init default 0
22322 * @cfg {Number} longitude Position when init default 0
22323 * @cfg {Number} zoom default 15
22324 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22325 * @cfg {Boolean} mapTypeControl default false
22326 * @cfg {Boolean} disableDoubleClickZoom default false
22327 * @cfg {Boolean} scrollwheel default true
22328 * @cfg {Boolean} streetViewControl default false
22329 * @cfg {Number} radius default 0
22330 * @cfg {String} locationName
22331 * @cfg {Boolean} draggable default true
22332 * @cfg {Boolean} enableAutocomplete default false
22333 * @cfg {Boolean} enableReverseGeocode default true
22334 * @cfg {String} markerTitle
22337 * Create a new LocationPicker
22338 * @param {Object} config The config object
22342 Roo.bootstrap.LocationPicker = function(config){
22344 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22349 * Fires when the picker initialized.
22350 * @param {Roo.bootstrap.LocationPicker} this
22351 * @param {Google Location} location
22355 * @event positionchanged
22356 * Fires when the picker position changed.
22357 * @param {Roo.bootstrap.LocationPicker} this
22358 * @param {Google Location} location
22360 positionchanged : true,
22363 * Fires when the map resize.
22364 * @param {Roo.bootstrap.LocationPicker} this
22369 * Fires when the map show.
22370 * @param {Roo.bootstrap.LocationPicker} this
22375 * Fires when the map hide.
22376 * @param {Roo.bootstrap.LocationPicker} this
22381 * Fires when click the map.
22382 * @param {Roo.bootstrap.LocationPicker} this
22383 * @param {Map event} e
22387 * @event mapRightClick
22388 * Fires when right click the map.
22389 * @param {Roo.bootstrap.LocationPicker} this
22390 * @param {Map event} e
22392 mapRightClick : true,
22394 * @event markerClick
22395 * Fires when click the marker.
22396 * @param {Roo.bootstrap.LocationPicker} this
22397 * @param {Map event} e
22399 markerClick : true,
22401 * @event markerRightClick
22402 * Fires when right click the marker.
22403 * @param {Roo.bootstrap.LocationPicker} this
22404 * @param {Map event} e
22406 markerRightClick : true,
22408 * @event OverlayViewDraw
22409 * Fires when OverlayView Draw
22410 * @param {Roo.bootstrap.LocationPicker} this
22412 OverlayViewDraw : true,
22414 * @event OverlayViewOnAdd
22415 * Fires when OverlayView Draw
22416 * @param {Roo.bootstrap.LocationPicker} this
22418 OverlayViewOnAdd : true,
22420 * @event OverlayViewOnRemove
22421 * Fires when OverlayView Draw
22422 * @param {Roo.bootstrap.LocationPicker} this
22424 OverlayViewOnRemove : true,
22426 * @event OverlayViewShow
22427 * Fires when OverlayView Draw
22428 * @param {Roo.bootstrap.LocationPicker} this
22429 * @param {Pixel} cpx
22431 OverlayViewShow : true,
22433 * @event OverlayViewHide
22434 * Fires when OverlayView Draw
22435 * @param {Roo.bootstrap.LocationPicker} this
22437 OverlayViewHide : true
22442 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22444 gMapContext: false,
22450 mapTypeControl: false,
22451 disableDoubleClickZoom: false,
22453 streetViewControl: false,
22457 enableAutocomplete: false,
22458 enableReverseGeocode: true,
22461 getAutoCreate: function()
22466 cls: 'roo-location-picker'
22472 initEvents: function(ct, position)
22474 if(!this.el.getWidth() || this.isApplied()){
22478 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22483 initial: function()
22485 if(!this.mapTypeId){
22486 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22489 this.gMapContext = this.GMapContext();
22491 this.initOverlayView();
22493 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22497 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22498 _this.setPosition(_this.gMapContext.marker.position);
22501 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22502 _this.fireEvent('mapClick', this, event);
22506 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22507 _this.fireEvent('mapRightClick', this, event);
22511 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22512 _this.fireEvent('markerClick', this, event);
22516 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22517 _this.fireEvent('markerRightClick', this, event);
22521 this.setPosition(this.gMapContext.location);
22523 this.fireEvent('initial', this, this.gMapContext.location);
22526 initOverlayView: function()
22530 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22534 _this.fireEvent('OverlayViewDraw', _this);
22539 _this.fireEvent('OverlayViewOnAdd', _this);
22542 onRemove: function()
22544 _this.fireEvent('OverlayViewOnRemove', _this);
22547 show: function(cpx)
22549 _this.fireEvent('OverlayViewShow', _this, cpx);
22554 _this.fireEvent('OverlayViewHide', _this);
22560 fromLatLngToContainerPixel: function(event)
22562 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22565 isApplied: function()
22567 return this.getGmapContext() == false ? false : true;
22570 getGmapContext: function()
22572 return this.gMapContext
22575 GMapContext: function()
22577 var position = new google.maps.LatLng(this.latitude, this.longitude);
22579 var _map = new google.maps.Map(this.el.dom, {
22582 mapTypeId: this.mapTypeId,
22583 mapTypeControl: this.mapTypeControl,
22584 disableDoubleClickZoom: this.disableDoubleClickZoom,
22585 scrollwheel: this.scrollwheel,
22586 streetViewControl: this.streetViewControl,
22587 locationName: this.locationName,
22588 draggable: this.draggable,
22589 enableAutocomplete: this.enableAutocomplete,
22590 enableReverseGeocode: this.enableReverseGeocode
22593 var _marker = new google.maps.Marker({
22594 position: position,
22596 title: this.markerTitle,
22597 draggable: this.draggable
22604 location: position,
22605 radius: this.radius,
22606 locationName: this.locationName,
22607 addressComponents: {
22608 formatted_address: null,
22609 addressLine1: null,
22610 addressLine2: null,
22612 streetNumber: null,
22616 stateOrProvince: null
22619 domContainer: this.el.dom,
22620 geodecoder: new google.maps.Geocoder()
22624 drawCircle: function(center, radius, options)
22626 if (this.gMapContext.circle != null) {
22627 this.gMapContext.circle.setMap(null);
22631 options = Roo.apply({}, options, {
22632 strokeColor: "#0000FF",
22633 strokeOpacity: .35,
22635 fillColor: "#0000FF",
22639 options.map = this.gMapContext.map;
22640 options.radius = radius;
22641 options.center = center;
22642 this.gMapContext.circle = new google.maps.Circle(options);
22643 return this.gMapContext.circle;
22649 setPosition: function(location)
22651 this.gMapContext.location = location;
22652 this.gMapContext.marker.setPosition(location);
22653 this.gMapContext.map.panTo(location);
22654 this.drawCircle(location, this.gMapContext.radius, {});
22658 if (this.gMapContext.settings.enableReverseGeocode) {
22659 this.gMapContext.geodecoder.geocode({
22660 latLng: this.gMapContext.location
22661 }, function(results, status) {
22663 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22664 _this.gMapContext.locationName = results[0].formatted_address;
22665 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22667 _this.fireEvent('positionchanged', this, location);
22674 this.fireEvent('positionchanged', this, location);
22679 google.maps.event.trigger(this.gMapContext.map, "resize");
22681 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22683 this.fireEvent('resize', this);
22686 setPositionByLatLng: function(latitude, longitude)
22688 this.setPosition(new google.maps.LatLng(latitude, longitude));
22691 getCurrentPosition: function()
22694 latitude: this.gMapContext.location.lat(),
22695 longitude: this.gMapContext.location.lng()
22699 getAddressName: function()
22701 return this.gMapContext.locationName;
22704 getAddressComponents: function()
22706 return this.gMapContext.addressComponents;
22709 address_component_from_google_geocode: function(address_components)
22713 for (var i = 0; i < address_components.length; i++) {
22714 var component = address_components[i];
22715 if (component.types.indexOf("postal_code") >= 0) {
22716 result.postalCode = component.short_name;
22717 } else if (component.types.indexOf("street_number") >= 0) {
22718 result.streetNumber = component.short_name;
22719 } else if (component.types.indexOf("route") >= 0) {
22720 result.streetName = component.short_name;
22721 } else if (component.types.indexOf("neighborhood") >= 0) {
22722 result.city = component.short_name;
22723 } else if (component.types.indexOf("locality") >= 0) {
22724 result.city = component.short_name;
22725 } else if (component.types.indexOf("sublocality") >= 0) {
22726 result.district = component.short_name;
22727 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22728 result.stateOrProvince = component.short_name;
22729 } else if (component.types.indexOf("country") >= 0) {
22730 result.country = component.short_name;
22734 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22735 result.addressLine2 = "";
22739 setZoomLevel: function(zoom)
22741 this.gMapContext.map.setZoom(zoom);
22754 this.fireEvent('show', this);
22765 this.fireEvent('hide', this);
22770 Roo.apply(Roo.bootstrap.LocationPicker, {
22772 OverlayView : function(map, options)
22774 options = options || {};
22788 * @class Roo.bootstrap.Alert
22789 * @extends Roo.bootstrap.Component
22790 * Bootstrap Alert class
22791 * @cfg {String} title The title of alert
22792 * @cfg {String} html The content of alert
22793 * @cfg {String} weight ( success | info | warning | danger )
22794 * @cfg {String} faicon font-awesomeicon
22797 * Create a new alert
22798 * @param {Object} config The config object
22802 Roo.bootstrap.Alert = function(config){
22803 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22807 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22814 getAutoCreate : function()
22823 cls : 'roo-alert-icon'
22828 cls : 'roo-alert-title',
22833 cls : 'roo-alert-text',
22840 cfg.cn[0].cls += ' fa ' + this.faicon;
22844 cfg.cls += ' alert-' + this.weight;
22850 initEvents: function()
22852 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22855 setTitle : function(str)
22857 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22860 setText : function(str)
22862 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22865 setWeight : function(weight)
22868 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22871 this.weight = weight;
22873 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22876 setIcon : function(icon)
22879 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22884 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);