4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
232 addxtypeChild : function (tree, cntr)
234 Roo.debug && Roo.log('addxtypeChild:' + cntr);
236 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
240 (typeof(tree['flexy:foreach']) != 'undefined');
244 skip_children = false;
245 // render the element if it's not BODY.
246 if (tree.xtype != 'Body') {
248 cn = Roo.factory(tree);
250 cn.parentType = this.xtype; //??
251 cn.parentId = this.id;
253 var build_from_html = Roo.XComponent.build_from_html;
256 // does the container contain child eleemnts with 'xtype' attributes.
257 // that match this xtype..
258 // note - when we render we create these as well..
259 // so we should check to see if body has xtype set.
260 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
262 var self_cntr_el = Roo.get(this[cntr](false));
263 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
265 Roo.log(Roo.XComponent.build_from_html);
266 Roo.log("got echild:");
269 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
270 // and are not displayed -this causes this to use up the wrong element when matching.
271 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
274 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
275 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
281 //echild.dom.removeAttribute('xtype');
283 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
284 Roo.debug && Roo.log(self_cntr_el);
285 Roo.debug && Roo.log(echild);
286 Roo.debug && Roo.log(cn);
292 // if object has flexy:if - then it may or may not be rendered.
293 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
294 // skip a flexy if element.
295 Roo.debug && Roo.log('skipping render');
296 Roo.debug && Roo.log(tree);
298 Roo.debug && Roo.log('skipping all children');
299 skip_children = true;
304 // actually if flexy:foreach is found, we really want to create
305 // multiple copies here...
307 //Roo.log(this[cntr]());
308 cn.render(this[cntr](true));
310 // then add the element..
318 if (typeof (tree.menu) != 'undefined') {
319 tree.menu.parentType = cn.xtype;
320 tree.menu.triggerEl = cn.el;
321 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
325 if (!tree.items || !tree.items.length) {
329 var items = tree.items;
332 //Roo.log(items.length);
334 if (!skip_children) {
335 for(var i =0;i < items.length;i++) {
336 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
342 this.fireEvent('childrenrendered', this);
358 * @class Roo.bootstrap.Body
359 * @extends Roo.bootstrap.Component
360 * Bootstrap Body class
364 * @param {Object} config The config object
367 Roo.bootstrap.Body = function(config){
368 Roo.bootstrap.Body.superclass.constructor.call(this, config);
369 this.el = Roo.get(document.body);
370 if (this.cls && this.cls.length) {
371 Roo.get(document.body).addClass(this.cls);
375 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
380 onRender : function(ct, position)
382 /* Roo.log("Roo.bootstrap.Body - onRender");
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
404 * @class Roo.bootstrap.ButtonGroup
405 * @extends Roo.bootstrap.Component
406 * Bootstrap ButtonGroup class
407 * @cfg {String} size lg | sm | xs (default empty normal)
408 * @cfg {String} align vertical | justified (default none)
409 * @cfg {String} direction up | down (default down)
410 * @cfg {Boolean} toolbar false | true
411 * @cfg {Boolean} btn true | false
416 * @param {Object} config The config object
419 Roo.bootstrap.ButtonGroup = function(config){
420 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
423 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
431 getAutoCreate : function(){
437 cfg.html = this.html || cfg.html;
448 if (['vertical','justified'].indexOf(this.align)!==-1) {
449 cfg.cls = 'btn-group-' + this.align;
451 if (this.align == 'justified') {
452 console.log(this.items);
456 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
457 cfg.cls += ' btn-group-' + this.size;
460 if (this.direction == 'up') {
461 cfg.cls += ' dropup' ;
477 * @class Roo.bootstrap.Button
478 * @extends Roo.bootstrap.Component
479 * Bootstrap Button class
480 * @cfg {String} html The button content
481 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
482 * @cfg {String} size ( lg | sm | xs)
483 * @cfg {String} tag ( a | input | submit)
484 * @cfg {String} href empty or href
485 * @cfg {Boolean} disabled default false;
486 * @cfg {Boolean} isClose default false;
487 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
488 * @cfg {String} badge text for badge
489 * @cfg {String} theme default
490 * @cfg {Boolean} inverse
491 * @cfg {Boolean} toggle
492 * @cfg {String} ontext text for on toggle state
493 * @cfg {String} offtext text for off toggle state
494 * @cfg {Boolean} defaulton
495 * @cfg {Boolean} preventDefault default true
496 * @cfg {Boolean} removeClass remove the standard class..
497 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
500 * Create a new button
501 * @param {Object} config The config object
505 Roo.bootstrap.Button = function(config){
506 Roo.bootstrap.Button.superclass.constructor.call(this, config);
511 * When a butotn is pressed
512 * @param {Roo.bootstrap.Button} this
513 * @param {Roo.EventObject} e
518 * After the button has been toggles
519 * @param {Roo.EventObject} e
520 * @param {boolean} pressed (also available as button.pressed)
526 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
544 preventDefault: true,
553 getAutoCreate : function(){
561 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
562 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
567 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
569 if (this.toggle == true) {
572 cls: 'slider-frame roo-button',
577 'data-off-text':'OFF',
578 cls: 'slider-button',
584 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585 cfg.cls += ' '+this.weight;
594 cfg["aria-hidden"] = true;
596 cfg.html = "×";
602 if (this.theme==='default') {
603 cfg.cls = 'btn roo-button';
605 //if (this.parentType != 'Navbar') {
606 this.weight = this.weight.length ? this.weight : 'default';
608 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
610 cfg.cls += ' btn-' + this.weight;
612 } else if (this.theme==='glow') {
615 cfg.cls = 'btn-glow roo-button';
617 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
619 cfg.cls += ' ' + this.weight;
625 this.cls += ' inverse';
630 cfg.cls += ' active';
634 cfg.disabled = 'disabled';
638 Roo.log('changing to ul' );
640 this.glyphicon = 'caret';
643 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
645 //gsRoo.log(this.parentType);
646 if (this.parentType === 'Navbar' && !this.parent().bar) {
647 Roo.log('changing to li?');
656 href : this.href || '#'
659 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
660 cfg.cls += ' dropdown';
667 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
669 if (this.glyphicon) {
670 cfg.html = ' ' + cfg.html;
675 cls: 'glyphicon glyphicon-' + this.glyphicon
685 // cfg.cls='btn roo-button';
689 var value = cfg.html;
694 cls: 'glyphicon glyphicon-' + this.glyphicon,
713 cfg.cls += ' dropdown';
714 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
717 if (cfg.tag !== 'a' && this.href !== '') {
718 throw "Tag must be a to set href.";
719 } else if (this.href.length > 0) {
720 cfg.href = this.href;
723 if(this.removeClass){
728 cfg.target = this.target;
733 initEvents: function() {
734 // Roo.log('init events?');
735 // Roo.log(this.el.dom);
738 if (typeof (this.menu) != 'undefined') {
739 this.menu.parentType = this.xtype;
740 this.menu.triggerEl = this.el;
741 this.addxtype(Roo.apply({}, this.menu));
745 if (this.el.hasClass('roo-button')) {
746 this.el.on('click', this.onClick, this);
748 this.el.select('.roo-button').on('click', this.onClick, this);
751 if(this.removeClass){
752 this.el.on('click', this.onClick, this);
755 this.el.enableDisplayMode();
758 onClick : function(e)
765 Roo.log('button on click ');
766 if(this.preventDefault){
769 if (this.pressed === true || this.pressed === false) {
770 this.pressed = !this.pressed;
771 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
772 this.fireEvent('toggle', this, e, this.pressed);
776 this.fireEvent('click', this, e);
780 * Enables this button
784 this.disabled = false;
785 this.el.removeClass('disabled');
789 * Disable this button
793 this.disabled = true;
794 this.el.addClass('disabled');
797 * sets the active state on/off,
798 * @param {Boolean} state (optional) Force a particular state
800 setActive : function(v) {
802 this.el[v ? 'addClass' : 'removeClass']('active');
805 * toggles the current active state
807 toggleActive : function()
809 var active = this.el.hasClass('active');
810 this.setActive(!active);
814 setText : function(str)
816 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
820 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
843 * @class Roo.bootstrap.Column
844 * @extends Roo.bootstrap.Component
845 * Bootstrap Column class
846 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
847 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
848 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
849 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
850 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
851 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
852 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
853 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
856 * @cfg {Boolean} hidden (true|false) hide the element
857 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
858 * @cfg {String} fa (ban|check|...) font awesome icon
859 * @cfg {Number} fasize (1|2|....) font awsome size
861 * @cfg {String} icon (info-sign|check|...) glyphicon name
863 * @cfg {String} html content of column.
866 * Create a new Column
867 * @param {Object} config The config object
870 Roo.bootstrap.Column = function(config){
871 Roo.bootstrap.Column.superclass.constructor.call(this, config);
874 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
892 getAutoCreate : function(){
893 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
901 ['xs','sm','md','lg'].map(function(size){
902 //Roo.log( size + ':' + settings[size]);
904 if (settings[size+'off'] !== false) {
905 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
908 if (settings[size] === false) {
911 Roo.log(settings[size]);
912 if (!settings[size]) { // 0 = hidden
913 cfg.cls += ' hidden-' + size;
916 cfg.cls += ' col-' + size + '-' + settings[size];
921 cfg.cls += ' hidden';
924 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
925 cfg.cls +=' alert alert-' + this.alert;
929 if (this.html.length) {
930 cfg.html = this.html;
934 if (this.fasize > 1) {
935 fasize = ' fa-' + this.fasize + 'x';
937 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
942 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
961 * @class Roo.bootstrap.Container
962 * @extends Roo.bootstrap.Component
963 * Bootstrap Container class
964 * @cfg {Boolean} jumbotron is it a jumbotron element
965 * @cfg {String} html content of element
966 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
967 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
968 * @cfg {String} header content of header (for panel)
969 * @cfg {String} footer content of footer (for panel)
970 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
971 * @cfg {String} tag (header|aside|section) type of HTML tag.
972 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
973 * @cfg {String} fa (ban|check|...) font awesome icon
974 * @cfg {String} icon (info-sign|check|...) glyphicon name
975 * @cfg {Boolean} hidden (true|false) hide the element
979 * Create a new Container
980 * @param {Object} config The config object
983 Roo.bootstrap.Container = function(config){
984 Roo.bootstrap.Container.superclass.constructor.call(this, config);
987 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1001 getChildContainer : function() {
1007 if (this.panel.length) {
1008 return this.el.select('.panel-body',true).first();
1015 getAutoCreate : function(){
1018 tag : this.tag || 'div',
1022 if (this.jumbotron) {
1023 cfg.cls = 'jumbotron';
1028 // - this is applied by the parent..
1030 // cfg.cls = this.cls + '';
1033 if (this.sticky.length) {
1035 var bd = Roo.get(document.body);
1036 if (!bd.hasClass('bootstrap-sticky')) {
1037 bd.addClass('bootstrap-sticky');
1038 Roo.select('html',true).setStyle('height', '100%');
1041 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1045 if (this.well.length) {
1046 switch (this.well) {
1049 cfg.cls +=' well well-' +this.well;
1058 cfg.cls += ' hidden';
1062 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1063 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.panel.length) {
1069 cfg.cls += ' panel panel-' + this.panel;
1071 if (this.header.length) {
1074 cls : 'panel-heading',
1077 cls : 'panel-title',
1090 if (this.footer.length) {
1092 cls : 'panel-footer',
1101 body.html = this.html || cfg.html;
1102 // prefix with the icons..
1104 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1107 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1112 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1113 cfg.cls = 'container';
1119 titleEl : function()
1121 if(!this.el || !this.panel.length || !this.header.length){
1125 return this.el.select('.panel-title',true).first();
1128 setTitle : function(v)
1130 var titleEl = this.titleEl();
1136 titleEl.dom.innerHTML = v;
1139 getTitle : function()
1142 var titleEl = this.titleEl();
1148 return titleEl.dom.innerHTML;
1152 this.el.removeClass('hidden');
1155 if (!this.el.hasClass('hidden')) {
1156 this.el.addClass('hidden');
1172 * @class Roo.bootstrap.Img
1173 * @extends Roo.bootstrap.Component
1174 * Bootstrap Img class
1175 * @cfg {Boolean} imgResponsive false | true
1176 * @cfg {String} border rounded | circle | thumbnail
1177 * @cfg {String} src image source
1178 * @cfg {String} alt image alternative text
1179 * @cfg {String} href a tag href
1180 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1183 * Create a new Input
1184 * @param {Object} config The config object
1187 Roo.bootstrap.Img = function(config){
1188 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1194 * The img click event for the img.
1195 * @param {Roo.EventObject} e
1201 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1203 imgResponsive: true,
1209 getAutoCreate : function(){
1213 cls: (this.imgResponsive) ? 'img-responsive' : '',
1217 cfg.html = this.html || cfg.html;
1219 cfg.src = this.src || cfg.src;
1221 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1222 cfg.cls += ' img-' + this.border;
1239 a.target = this.target;
1245 return (this.href) ? a : cfg;
1248 initEvents: function() {
1251 this.el.on('click', this.onClick, this);
1255 onClick : function(e)
1257 Roo.log('img onclick');
1258 this.fireEvent('click', this, e);
1272 * @class Roo.bootstrap.Link
1273 * @extends Roo.bootstrap.Component
1274 * Bootstrap Link Class
1275 * @cfg {String} alt image alternative text
1276 * @cfg {String} href a tag href
1277 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1278 * @cfg {String} html the content of the link.
1279 * @cfg {String} anchor name for the anchor link
1281 * @cfg {Boolean} preventDefault (true | false) default false
1285 * Create a new Input
1286 * @param {Object} config The config object
1289 Roo.bootstrap.Link = function(config){
1290 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1296 * The img click event for the img.
1297 * @param {Roo.EventObject} e
1303 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1307 preventDefault: false,
1311 getAutoCreate : function()
1317 // anchor's do not require html/href...
1318 if (this.anchor === false) {
1319 cfg.html = this.html || 'html-missing';
1320 cfg.href = this.href || '#';
1322 cfg.name = this.anchor;
1323 if (this.html !== false) {
1324 cfg.html = this.html;
1326 if (this.href !== false) {
1327 cfg.href = this.href;
1331 if(this.alt !== false){
1336 if(this.target !== false) {
1337 cfg.target = this.target;
1343 initEvents: function() {
1345 if(!this.href || this.preventDefault){
1346 this.el.on('click', this.onClick, this);
1350 onClick : function(e)
1352 if(this.preventDefault){
1355 //Roo.log('img onclick');
1356 this.fireEvent('click', this, e);
1369 * @class Roo.bootstrap.Header
1370 * @extends Roo.bootstrap.Component
1371 * Bootstrap Header class
1372 * @cfg {String} html content of header
1373 * @cfg {Number} level (1|2|3|4|5|6) default 1
1376 * Create a new Header
1377 * @param {Object} config The config object
1381 Roo.bootstrap.Header = function(config){
1382 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1385 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1393 getAutoCreate : function(){
1398 tag: 'h' + (1 *this.level),
1399 html: this.html || ''
1411 * Ext JS Library 1.1.1
1412 * Copyright(c) 2006-2007, Ext JS, LLC.
1414 * Originally Released Under LGPL - original licence link has changed is not relivant.
1417 * <script type="text/javascript">
1421 * @class Roo.bootstrap.MenuMgr
1422 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1425 Roo.bootstrap.MenuMgr = function(){
1426 var menus, active, groups = {}, attached = false, lastShow = new Date();
1428 // private - called when first menu is created
1431 active = new Roo.util.MixedCollection();
1432 Roo.get(document).addKeyListener(27, function(){
1433 if(active.length > 0){
1441 if(active && active.length > 0){
1442 var c = active.clone();
1452 if(active.length < 1){
1453 Roo.get(document).un("mouseup", onMouseDown);
1461 var last = active.last();
1462 lastShow = new Date();
1465 Roo.get(document).on("mouseup", onMouseDown);
1470 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1471 m.parentMenu.activeChild = m;
1472 }else if(last && last.isVisible()){
1473 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1478 function onBeforeHide(m){
1480 m.activeChild.hide();
1482 if(m.autoHideTimer){
1483 clearTimeout(m.autoHideTimer);
1484 delete m.autoHideTimer;
1489 function onBeforeShow(m){
1490 var pm = m.parentMenu;
1491 if(!pm && !m.allowOtherMenus){
1493 }else if(pm && pm.activeChild && active != m){
1494 pm.activeChild.hide();
1499 function onMouseDown(e){
1500 Roo.log("on MouseDown");
1501 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1509 function onBeforeCheck(mi, state){
1511 var g = groups[mi.group];
1512 for(var i = 0, l = g.length; i < l; i++){
1514 g[i].setChecked(false);
1523 * Hides all menus that are currently visible
1525 hideAll : function(){
1530 register : function(menu){
1534 menus[menu.id] = menu;
1535 menu.on("beforehide", onBeforeHide);
1536 menu.on("hide", onHide);
1537 menu.on("beforeshow", onBeforeShow);
1538 menu.on("show", onShow);
1540 if(g && menu.events["checkchange"]){
1544 groups[g].push(menu);
1545 menu.on("checkchange", onCheck);
1550 * Returns a {@link Roo.menu.Menu} object
1551 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1552 * be used to generate and return a new Menu instance.
1554 get : function(menu){
1555 if(typeof menu == "string"){ // menu id
1557 }else if(menu.events){ // menu instance
1560 /*else if(typeof menu.length == 'number'){ // array of menu items?
1561 return new Roo.bootstrap.Menu({items:menu});
1562 }else{ // otherwise, must be a config
1563 return new Roo.bootstrap.Menu(menu);
1570 unregister : function(menu){
1571 delete menus[menu.id];
1572 menu.un("beforehide", onBeforeHide);
1573 menu.un("hide", onHide);
1574 menu.un("beforeshow", onBeforeShow);
1575 menu.un("show", onShow);
1577 if(g && menu.events["checkchange"]){
1578 groups[g].remove(menu);
1579 menu.un("checkchange", onCheck);
1584 registerCheckable : function(menuItem){
1585 var g = menuItem.group;
1590 groups[g].push(menuItem);
1591 menuItem.on("beforecheckchange", onBeforeCheck);
1596 unregisterCheckable : function(menuItem){
1597 var g = menuItem.group;
1599 groups[g].remove(menuItem);
1600 menuItem.un("beforecheckchange", onBeforeCheck);
1612 * @class Roo.bootstrap.Menu
1613 * @extends Roo.bootstrap.Component
1614 * Bootstrap Menu class - container for MenuItems
1615 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1619 * @param {Object} config The config object
1623 Roo.bootstrap.Menu = function(config){
1624 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1625 if (this.registerMenu) {
1626 Roo.bootstrap.MenuMgr.register(this);
1631 * Fires before this menu is displayed
1632 * @param {Roo.menu.Menu} this
1637 * Fires before this menu is hidden
1638 * @param {Roo.menu.Menu} this
1643 * Fires after this menu is displayed
1644 * @param {Roo.menu.Menu} this
1649 * Fires after this menu is hidden
1650 * @param {Roo.menu.Menu} this
1655 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1656 * @param {Roo.menu.Menu} this
1657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658 * @param {Roo.EventObject} e
1663 * Fires when the mouse is hovering over this menu
1664 * @param {Roo.menu.Menu} this
1665 * @param {Roo.EventObject} e
1666 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1671 * Fires when the mouse exits this menu
1672 * @param {Roo.menu.Menu} this
1673 * @param {Roo.EventObject} e
1674 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1679 * Fires when a menu item contained in this menu is clicked
1680 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1681 * @param {Roo.EventObject} e
1685 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1688 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1692 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1695 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1697 registerMenu : true,
1699 menuItems :false, // stores the menu items..
1705 getChildContainer : function() {
1709 getAutoCreate : function(){
1711 //if (['right'].indexOf(this.align)!==-1) {
1712 // cfg.cn[1].cls += ' pull-right'
1718 cls : 'dropdown-menu' ,
1719 style : 'z-index:1000'
1723 if (this.type === 'submenu') {
1724 cfg.cls = 'submenu active';
1726 if (this.type === 'treeview') {
1727 cfg.cls = 'treeview-menu';
1732 initEvents : function() {
1734 // Roo.log("ADD event");
1735 // Roo.log(this.triggerEl.dom);
1736 this.triggerEl.on('click', this.onTriggerPress, this);
1737 this.triggerEl.addClass('dropdown-toggle');
1738 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1740 this.el.on("mouseover", this.onMouseOver, this);
1741 this.el.on("mouseout", this.onMouseOut, this);
1745 findTargetItem : function(e){
1746 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1750 //Roo.log(t); Roo.log(t.id);
1752 //Roo.log(this.menuitems);
1753 return this.menuitems.get(t.id);
1755 //return this.items.get(t.menuItemId);
1760 onClick : function(e){
1761 Roo.log("menu.onClick");
1762 var t = this.findTargetItem(e);
1763 if(!t || t.isContainer){
1768 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1769 if(t == this.activeItem && t.shouldDeactivate(e)){
1770 this.activeItem.deactivate();
1771 delete this.activeItem;
1775 this.setActiveItem(t, true);
1783 Roo.log('pass click event');
1787 this.fireEvent("click", this, t, e);
1791 onMouseOver : function(e){
1792 var t = this.findTargetItem(e);
1795 // if(t.canActivate && !t.disabled){
1796 // this.setActiveItem(t, true);
1800 this.fireEvent("mouseover", this, e, t);
1802 isVisible : function(){
1803 return !this.hidden;
1805 onMouseOut : function(e){
1806 var t = this.findTargetItem(e);
1809 // if(t == this.activeItem && t.shouldDeactivate(e)){
1810 // this.activeItem.deactivate();
1811 // delete this.activeItem;
1814 this.fireEvent("mouseout", this, e, t);
1819 * Displays this menu relative to another element
1820 * @param {String/HTMLElement/Roo.Element} element The element to align to
1821 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1822 * the element (defaults to this.defaultAlign)
1823 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1825 show : function(el, pos, parentMenu){
1826 this.parentMenu = parentMenu;
1830 this.fireEvent("beforeshow", this);
1831 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1834 * Displays this menu at a specific xy position
1835 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1836 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1838 showAt : function(xy, parentMenu, /* private: */_e){
1839 this.parentMenu = parentMenu;
1844 this.fireEvent("beforeshow", this);
1845 //xy = this.el.adjustForConstraints(xy);
1849 this.hideMenuItems();
1850 this.hidden = false;
1851 this.triggerEl.addClass('open');
1853 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1854 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1859 this.fireEvent("show", this);
1865 this.doFocus.defer(50, this);
1869 doFocus : function(){
1871 this.focusEl.focus();
1876 * Hides this menu and optionally all parent menus
1877 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1879 hide : function(deep){
1881 this.hideMenuItems();
1882 if(this.el && this.isVisible()){
1883 this.fireEvent("beforehide", this);
1884 if(this.activeItem){
1885 this.activeItem.deactivate();
1886 this.activeItem = null;
1888 this.triggerEl.removeClass('open');;
1890 this.fireEvent("hide", this);
1892 if(deep === true && this.parentMenu){
1893 this.parentMenu.hide(true);
1897 onTriggerPress : function(e)
1900 Roo.log('trigger press');
1901 //Roo.log(e.getTarget());
1902 // Roo.log(this.triggerEl.dom);
1903 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1906 if (this.isVisible()) {
1910 this.show(this.triggerEl, false, false);
1919 hideMenuItems : function()
1921 //$(backdrop).remove()
1922 Roo.select('.open',true).each(function(aa) {
1924 aa.removeClass('open');
1925 //var parent = getParent($(this))
1926 //var relatedTarget = { relatedTarget: this }
1928 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1929 //if (e.isDefaultPrevented()) return
1930 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1933 addxtypeChild : function (tree, cntr) {
1934 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1936 this.menuitems.add(comp);
1957 * @class Roo.bootstrap.MenuItem
1958 * @extends Roo.bootstrap.Component
1959 * Bootstrap MenuItem class
1960 * @cfg {String} html the menu label
1961 * @cfg {String} href the link
1962 * @cfg {Boolean} preventDefault (true | false) default true
1963 * @cfg {Boolean} isContainer (true | false) default false
1967 * Create a new MenuItem
1968 * @param {Object} config The config object
1972 Roo.bootstrap.MenuItem = function(config){
1973 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1978 * The raw click event for the entire grid.
1979 * @param {Roo.bootstrap.MenuItem} this
1980 * @param {Roo.EventObject} e
1986 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1990 preventDefault: true,
1991 isContainer : false,
1993 getAutoCreate : function(){
1995 if(this.isContainer){
1998 cls: 'dropdown-menu-item'
2004 cls: 'dropdown-menu-item',
2013 if (this.parent().type == 'treeview') {
2014 cfg.cls = 'treeview-menu';
2017 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2018 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2022 initEvents: function() {
2024 //this.el.select('a').on('click', this.onClick, this);
2027 onClick : function(e)
2029 Roo.log('item on click ');
2030 //if(this.preventDefault){
2031 // e.preventDefault();
2033 //this.parent().hideMenuItems();
2035 this.fireEvent('click', this, e);
2054 * @class Roo.bootstrap.MenuSeparator
2055 * @extends Roo.bootstrap.Component
2056 * Bootstrap MenuSeparator class
2059 * Create a new MenuItem
2060 * @param {Object} config The config object
2064 Roo.bootstrap.MenuSeparator = function(config){
2065 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2068 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2070 getAutoCreate : function(){
2089 * @class Roo.bootstrap.Modal
2090 * @extends Roo.bootstrap.Component
2091 * Bootstrap Modal class
2092 * @cfg {String} title Title of dialog
2093 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2094 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2095 * @cfg {Boolean} specificTitle default false
2096 * @cfg {Array} buttons Array of buttons or standard button set..
2097 * @cfg {String} buttonPosition (left|right|center) default right
2098 * @cfg {Boolean} animate default true
2099 * @cfg {Boolean} allow_close default true
2102 * Create a new Modal Dialog
2103 * @param {Object} config The config object
2106 Roo.bootstrap.Modal = function(config){
2107 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2112 * The raw btnclick event for the button
2113 * @param {Roo.EventObject} e
2117 this.buttons = this.buttons || [];
2120 this.tmpl = Roo.factory(this.tmpl);
2125 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2127 title : 'test dialog',
2137 specificTitle: false,
2139 buttonPosition: 'right',
2153 onRender : function(ct, position)
2155 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2158 var cfg = Roo.apply({}, this.getAutoCreate());
2161 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2163 //if (!cfg.name.length) {
2167 cfg.cls += ' ' + this.cls;
2170 cfg.style = this.style;
2172 this.el = Roo.get(document.body).createChild(cfg, position);
2174 //var type = this.el.dom.type;
2179 if(this.tabIndex !== undefined){
2180 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2184 this.bodyEl = this.el.select('.modal-body',true).first();
2185 this.closeEl = this.el.select('.modal-header .close', true).first();
2186 this.footerEl = this.el.select('.modal-footer',true).first();
2187 this.titleEl = this.el.select('.modal-title',true).first();
2191 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2192 this.maskEl.enableDisplayMode("block");
2194 //this.el.addClass("x-dlg-modal");
2196 if (this.buttons.length) {
2197 Roo.each(this.buttons, function(bb) {
2198 b = Roo.apply({}, bb);
2199 b.xns = b.xns || Roo.bootstrap;
2200 b.xtype = b.xtype || 'Button';
2201 if (typeof(b.listeners) == 'undefined') {
2202 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2205 var btn = Roo.factory(b);
2207 btn.onRender(this.el.select('.modal-footer div').first());
2211 // render the children.
2214 if(typeof(this.items) != 'undefined'){
2215 var items = this.items;
2218 for(var i =0;i < items.length;i++) {
2219 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2223 this.items = nitems;
2225 // where are these used - they used to be body/close/footer
2229 //this.el.addClass([this.fieldClass, this.cls]);
2232 getAutoCreate : function(){
2237 html : this.html || ''
2242 cls : 'modal-title',
2246 if(this.specificTitle){
2252 if (this.allow_close) {
2263 style : 'display: none',
2266 cls: "modal-dialog",
2269 cls : "modal-content",
2272 cls : 'modal-header',
2277 cls : 'modal-footer',
2281 cls: 'btn-' + this.buttonPosition
2298 modal.cls += ' fade';
2304 getChildContainer : function() {
2309 getButtonContainer : function() {
2310 return this.el.select('.modal-footer div',true).first();
2313 initEvents : function()
2315 if (this.allow_close) {
2316 this.closeEl.on('click', this.hide, this);
2322 if (!this.rendered) {
2326 this.el.setStyle('display', 'block');
2330 (function(){ _this.el.addClass('in'); }).defer(50);
2332 this.el.addClass('in');
2335 // not sure how we can show data in here..
2337 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2340 Roo.get(document.body).addClass("x-body-masked");
2341 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2343 this.el.setStyle('zIndex', '10001');
2345 this.fireEvent('show', this);
2352 Roo.get(document.body).removeClass("x-body-masked");
2353 this.el.removeClass('in');
2357 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2359 this.el.setStyle('display', 'none');
2362 this.fireEvent('hide', this);
2365 addButton : function(str, cb)
2369 var b = Roo.apply({}, { html : str } );
2370 b.xns = b.xns || Roo.bootstrap;
2371 b.xtype = b.xtype || 'Button';
2372 if (typeof(b.listeners) == 'undefined') {
2373 b.listeners = { click : cb.createDelegate(this) };
2376 var btn = Roo.factory(b);
2378 btn.onRender(this.el.select('.modal-footer div').first());
2384 setDefaultButton : function(btn)
2386 //this.el.select('.modal-footer').()
2388 resizeTo: function(w,h)
2392 setContentSize : function(w, h)
2396 onButtonClick: function(btn,e)
2399 this.fireEvent('btnclick', btn.name, e);
2402 * Set the title of the Dialog
2403 * @param {String} str new Title
2405 setTitle: function(str) {
2406 this.titleEl.dom.innerHTML = str;
2409 * Set the body of the Dialog
2410 * @param {String} str new Title
2412 setBody: function(str) {
2413 this.bodyEl.dom.innerHTML = str;
2416 * Set the body of the Dialog using the template
2417 * @param {Obj} data - apply this data to the template and replace the body contents.
2419 applyBody: function(obj)
2422 Roo.log("Error - using apply Body without a template");
2425 this.tmpl.overwrite(this.bodyEl, obj);
2431 Roo.apply(Roo.bootstrap.Modal, {
2433 * Button config that displays a single OK button
2442 * Button config that displays Yes and No buttons
2458 * Button config that displays OK and Cancel buttons
2473 * Button config that displays Yes, No and Cancel buttons
2496 * messagebox - can be used as a replace
2500 * @class Roo.MessageBox
2501 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2505 Roo.Msg.alert('Status', 'Changes saved successfully.');
2507 // Prompt for user data:
2508 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2510 // process text value...
2514 // Show a dialog using config options:
2516 title:'Save Changes?',
2517 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2518 buttons: Roo.Msg.YESNOCANCEL,
2525 Roo.bootstrap.MessageBox = function(){
2526 var dlg, opt, mask, waitTimer;
2527 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2528 var buttons, activeTextEl, bwidth;
2532 var handleButton = function(button){
2534 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2538 var handleHide = function(){
2540 dlg.el.removeClass(opt.cls);
2543 // Roo.TaskMgr.stop(waitTimer);
2544 // waitTimer = null;
2549 var updateButtons = function(b){
2552 buttons["ok"].hide();
2553 buttons["cancel"].hide();
2554 buttons["yes"].hide();
2555 buttons["no"].hide();
2556 //dlg.footer.dom.style.display = 'none';
2559 dlg.footerEl.dom.style.display = '';
2560 for(var k in buttons){
2561 if(typeof buttons[k] != "function"){
2564 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2565 width += buttons[k].el.getWidth()+15;
2575 var handleEsc = function(d, k, e){
2576 if(opt && opt.closable !== false){
2586 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2587 * @return {Roo.BasicDialog} The BasicDialog element
2589 getDialog : function(){
2591 dlg = new Roo.bootstrap.Modal( {
2594 //constraintoviewport:false,
2596 //collapsible : false,
2601 //buttonAlign:"center",
2602 closeClick : function(){
2603 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2606 handleButton("cancel");
2611 dlg.on("hide", handleHide);
2613 //dlg.addKeyListener(27, handleEsc);
2615 this.buttons = buttons;
2616 var bt = this.buttonText;
2617 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2618 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2619 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2620 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2622 bodyEl = dlg.bodyEl.createChild({
2624 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2625 '<textarea class="roo-mb-textarea"></textarea>' +
2626 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2628 msgEl = bodyEl.dom.firstChild;
2629 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2630 textboxEl.enableDisplayMode();
2631 textboxEl.addKeyListener([10,13], function(){
2632 if(dlg.isVisible() && opt && opt.buttons){
2635 }else if(opt.buttons.yes){
2636 handleButton("yes");
2640 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2641 textareaEl.enableDisplayMode();
2642 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2643 progressEl.enableDisplayMode();
2644 var pf = progressEl.dom.firstChild;
2646 pp = Roo.get(pf.firstChild);
2647 pp.setHeight(pf.offsetHeight);
2655 * Updates the message box body text
2656 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2657 * the XHTML-compliant non-breaking space character '&#160;')
2658 * @return {Roo.MessageBox} This message box
2660 updateText : function(text){
2661 if(!dlg.isVisible() && !opt.width){
2662 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2664 msgEl.innerHTML = text || ' ';
2666 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2667 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2669 Math.min(opt.width || cw , this.maxWidth),
2670 Math.max(opt.minWidth || this.minWidth, bwidth)
2673 activeTextEl.setWidth(w);
2675 if(dlg.isVisible()){
2676 dlg.fixedcenter = false;
2678 // to big, make it scroll. = But as usual stupid IE does not support
2681 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2682 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2683 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2685 bodyEl.dom.style.height = '';
2686 bodyEl.dom.style.overflowY = '';
2689 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2691 bodyEl.dom.style.overflowX = '';
2694 dlg.setContentSize(w, bodyEl.getHeight());
2695 if(dlg.isVisible()){
2696 dlg.fixedcenter = true;
2702 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2703 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2704 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2705 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2706 * @return {Roo.MessageBox} This message box
2708 updateProgress : function(value, text){
2710 this.updateText(text);
2712 if (pp) { // weird bug on my firefox - for some reason this is not defined
2713 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2719 * Returns true if the message box is currently displayed
2720 * @return {Boolean} True if the message box is visible, else false
2722 isVisible : function(){
2723 return dlg && dlg.isVisible();
2727 * Hides the message box if it is displayed
2730 if(this.isVisible()){
2736 * Displays a new message box, or reinitializes an existing message box, based on the config options
2737 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2738 * The following config object properties are supported:
2740 Property Type Description
2741 ---------- --------------- ------------------------------------------------------------------------------------
2742 animEl String/Element An id or Element from which the message box should animate as it opens and
2743 closes (defaults to undefined)
2744 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2745 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2746 closable Boolean False to hide the top-right close button (defaults to true). Note that
2747 progress and wait dialogs will ignore this property and always hide the
2748 close button as they can only be closed programmatically.
2749 cls String A custom CSS class to apply to the message box element
2750 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2751 displayed (defaults to 75)
2752 fn Function A callback function to execute after closing the dialog. The arguments to the
2753 function will be btn (the name of the button that was clicked, if applicable,
2754 e.g. "ok"), and text (the value of the active text field, if applicable).
2755 Progress and wait dialogs will ignore this option since they do not respond to
2756 user actions and can only be closed programmatically, so any required function
2757 should be called by the same code after it closes the dialog.
2758 icon String A CSS class that provides a background image to be used as an icon for
2759 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2760 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2761 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2762 modal Boolean False to allow user interaction with the page while the message box is
2763 displayed (defaults to true)
2764 msg String A string that will replace the existing message box body text (defaults
2765 to the XHTML-compliant non-breaking space character ' ')
2766 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2767 progress Boolean True to display a progress bar (defaults to false)
2768 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2769 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2770 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2771 title String The title text
2772 value String The string value to set into the active textbox element if displayed
2773 wait Boolean True to display a progress bar (defaults to false)
2774 width Number The width of the dialog in pixels
2781 msg: 'Please enter your address:',
2783 buttons: Roo.MessageBox.OKCANCEL,
2786 animEl: 'addAddressBtn'
2789 * @param {Object} config Configuration options
2790 * @return {Roo.MessageBox} This message box
2792 show : function(options)
2795 // this causes nightmares if you show one dialog after another
2796 // especially on callbacks..
2798 if(this.isVisible()){
2801 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2802 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2803 Roo.log("New Dialog Message:" + options.msg )
2804 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2805 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2808 var d = this.getDialog();
2810 d.setTitle(opt.title || " ");
2811 d.closeEl.setDisplayed(opt.closable !== false);
2812 activeTextEl = textboxEl;
2813 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2818 textareaEl.setHeight(typeof opt.multiline == "number" ?
2819 opt.multiline : this.defaultTextHeight);
2820 activeTextEl = textareaEl;
2829 progressEl.setDisplayed(opt.progress === true);
2830 this.updateProgress(0);
2831 activeTextEl.dom.value = opt.value || "";
2833 dlg.setDefaultButton(activeTextEl);
2835 var bs = opt.buttons;
2839 }else if(bs && bs.yes){
2840 db = buttons["yes"];
2842 dlg.setDefaultButton(db);
2844 bwidth = updateButtons(opt.buttons);
2845 this.updateText(opt.msg);
2847 d.el.addClass(opt.cls);
2849 d.proxyDrag = opt.proxyDrag === true;
2850 d.modal = opt.modal !== false;
2851 d.mask = opt.modal !== false ? mask : false;
2853 // force it to the end of the z-index stack so it gets a cursor in FF
2854 document.body.appendChild(dlg.el.dom);
2855 d.animateTarget = null;
2856 d.show(options.animEl);
2862 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2863 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2864 * and closing the message box when the process is complete.
2865 * @param {String} title The title bar text
2866 * @param {String} msg The message box body text
2867 * @return {Roo.MessageBox} This message box
2869 progress : function(title, msg){
2876 minWidth: this.minProgressWidth,
2883 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2884 * If a callback function is passed it will be called after the user clicks the button, and the
2885 * id of the button that was clicked will be passed as the only parameter to the callback
2886 * (could also be the top-right close button).
2887 * @param {String} title The title bar text
2888 * @param {String} msg The message box body text
2889 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2890 * @param {Object} scope (optional) The scope of the callback function
2891 * @return {Roo.MessageBox} This message box
2893 alert : function(title, msg, fn, scope){
2906 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2907 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2908 * You are responsible for closing the message box when the process is complete.
2909 * @param {String} msg The message box body text
2910 * @param {String} title (optional) The title bar text
2911 * @return {Roo.MessageBox} This message box
2913 wait : function(msg, title){
2924 waitTimer = Roo.TaskMgr.start({
2926 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2934 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2935 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2936 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2937 * @param {String} title The title bar text
2938 * @param {String} msg The message box body text
2939 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2940 * @param {Object} scope (optional) The scope of the callback function
2941 * @return {Roo.MessageBox} This message box
2943 confirm : function(title, msg, fn, scope){
2947 buttons: this.YESNO,
2956 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2957 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2958 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2959 * (could also be the top-right close button) and the text that was entered will be passed as the two
2960 * parameters to the callback.
2961 * @param {String} title The title bar text
2962 * @param {String} msg The message box body text
2963 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2964 * @param {Object} scope (optional) The scope of the callback function
2965 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2966 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2967 * @return {Roo.MessageBox} This message box
2969 prompt : function(title, msg, fn, scope, multiline){
2973 buttons: this.OKCANCEL,
2978 multiline: multiline,
2985 * Button config that displays a single OK button
2990 * Button config that displays Yes and No buttons
2993 YESNO : {yes:true, no:true},
2995 * Button config that displays OK and Cancel buttons
2998 OKCANCEL : {ok:true, cancel:true},
3000 * Button config that displays Yes, No and Cancel buttons
3003 YESNOCANCEL : {yes:true, no:true, cancel:true},
3006 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3009 defaultTextHeight : 75,
3011 * The maximum width in pixels of the message box (defaults to 600)
3016 * The minimum width in pixels of the message box (defaults to 100)
3021 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3022 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3025 minProgressWidth : 250,
3027 * An object containing the default button text strings that can be overriden for localized language support.
3028 * Supported properties are: ok, cancel, yes and no.
3029 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3042 * Shorthand for {@link Roo.MessageBox}
3044 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3045 Roo.Msg = Roo.Msg || Roo.MessageBox;
3054 * @class Roo.bootstrap.Navbar
3055 * @extends Roo.bootstrap.Component
3056 * Bootstrap Navbar class
3059 * Create a new Navbar
3060 * @param {Object} config The config object
3064 Roo.bootstrap.Navbar = function(config){
3065 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3069 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3078 getAutoCreate : function(){
3081 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3085 initEvents :function ()
3087 //Roo.log(this.el.select('.navbar-toggle',true));
3088 this.el.select('.navbar-toggle',true).on('click', function() {
3089 // Roo.log('click');
3090 this.el.select('.navbar-collapse',true).toggleClass('in');
3098 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3100 var size = this.el.getSize();
3101 this.maskEl.setSize(size.width, size.height);
3102 this.maskEl.enableDisplayMode("block");
3111 getChildContainer : function()
3113 if (this.el.select('.collapse').getCount()) {
3114 return this.el.select('.collapse',true).first();
3147 * @class Roo.bootstrap.NavSimplebar
3148 * @extends Roo.bootstrap.Navbar
3149 * Bootstrap Sidebar class
3151 * @cfg {Boolean} inverse is inverted color
3153 * @cfg {String} type (nav | pills | tabs)
3154 * @cfg {Boolean} arrangement stacked | justified
3155 * @cfg {String} align (left | right) alignment
3157 * @cfg {Boolean} main (true|false) main nav bar? default false
3158 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3160 * @cfg {String} tag (header|footer|nav|div) default is nav
3166 * Create a new Sidebar
3167 * @param {Object} config The config object
3171 Roo.bootstrap.NavSimplebar = function(config){
3172 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3175 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3191 getAutoCreate : function(){
3195 tag : this.tag || 'div',
3208 this.type = this.type || 'nav';
3209 if (['tabs','pills'].indexOf(this.type)!==-1) {
3210 cfg.cn[0].cls += ' nav-' + this.type
3214 if (this.type!=='nav') {
3215 Roo.log('nav type must be nav/tabs/pills')
3217 cfg.cn[0].cls += ' navbar-nav'
3223 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3224 cfg.cn[0].cls += ' nav-' + this.arrangement;
3228 if (this.align === 'right') {
3229 cfg.cn[0].cls += ' navbar-right';
3233 cfg.cls += ' navbar-inverse';
3260 * @class Roo.bootstrap.NavHeaderbar
3261 * @extends Roo.bootstrap.NavSimplebar
3262 * Bootstrap Sidebar class
3264 * @cfg {String} brand what is brand
3265 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3266 * @cfg {String} brand_href href of the brand
3267 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3268 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3269 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3270 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3273 * Create a new Sidebar
3274 * @param {Object} config The config object
3278 Roo.bootstrap.NavHeaderbar = function(config){
3279 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3283 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3290 desktopCenter : false,
3293 getAutoCreate : function(){
3296 tag: this.nav || 'nav',
3303 if (this.desktopCenter) {
3304 cn.push({cls : 'container', cn : []});
3311 cls: 'navbar-header',
3316 cls: 'navbar-toggle',
3317 'data-toggle': 'collapse',
3322 html: 'Toggle navigation'
3344 cls: 'collapse navbar-collapse',
3348 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3350 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3351 cfg.cls += ' navbar-' + this.position;
3353 // tag can override this..
3355 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3358 if (this.brand !== '') {
3361 href: this.brand_href ? this.brand_href : '#',
3362 cls: 'navbar-brand',
3370 cfg.cls += ' main-nav';
3378 getHeaderChildContainer : function()
3380 if (this.el.select('.navbar-header').getCount()) {
3381 return this.el.select('.navbar-header',true).first();
3384 return this.getChildContainer();
3388 initEvents : function()
3390 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3392 if (this.autohide) {
3397 Roo.get(document).on('scroll',function(e) {
3398 var ns = Roo.get(document).getScroll().top;
3399 var os = prevScroll;
3403 ft.removeClass('slideDown');
3404 ft.addClass('slideUp');
3407 ft.removeClass('slideUp');
3408 ft.addClass('slideDown');
3432 * @class Roo.bootstrap.NavSidebar
3433 * @extends Roo.bootstrap.Navbar
3434 * Bootstrap Sidebar class
3437 * Create a new Sidebar
3438 * @param {Object} config The config object
3442 Roo.bootstrap.NavSidebar = function(config){
3443 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3446 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3448 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3450 getAutoCreate : function(){
3455 cls: 'sidebar sidebar-nav'
3477 * @class Roo.bootstrap.NavGroup
3478 * @extends Roo.bootstrap.Component
3479 * Bootstrap NavGroup class
3480 * @cfg {String} align left | right
3481 * @cfg {Boolean} inverse false | true
3482 * @cfg {String} type (nav|pills|tab) default nav
3483 * @cfg {String} navId - reference Id for navbar.
3487 * Create a new nav group
3488 * @param {Object} config The config object
3491 Roo.bootstrap.NavGroup = function(config){
3492 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3495 Roo.bootstrap.NavGroup.register(this);
3499 * Fires when the active item changes
3500 * @param {Roo.bootstrap.NavGroup} this
3501 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3502 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3509 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3520 getAutoCreate : function()
3522 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3529 if (['tabs','pills'].indexOf(this.type)!==-1) {
3530 cfg.cls += ' nav-' + this.type
3532 if (this.type!=='nav') {
3533 Roo.log('nav type must be nav/tabs/pills')
3535 cfg.cls += ' navbar-nav'
3538 if (this.parent().sidebar) {
3541 cls: 'dashboard-menu sidebar-menu'
3547 if (this.form === true) {
3553 if (this.align === 'right') {
3554 cfg.cls += ' navbar-right';
3556 cfg.cls += ' navbar-left';
3560 if (this.align === 'right') {
3561 cfg.cls += ' navbar-right';
3565 cfg.cls += ' navbar-inverse';
3573 * sets the active Navigation item
3574 * @param {Roo.bootstrap.NavItem} the new current navitem
3576 setActiveItem : function(item)
3579 Roo.each(this.navItems, function(v){
3584 v.setActive(false, true);
3591 item.setActive(true, true);
3592 this.fireEvent('changed', this, item, prev);
3597 * gets the active Navigation item
3598 * @return {Roo.bootstrap.NavItem} the current navitem
3600 getActive : function()
3604 Roo.each(this.navItems, function(v){
3615 indexOfNav : function()
3619 Roo.each(this.navItems, function(v,i){
3630 * adds a Navigation item
3631 * @param {Roo.bootstrap.NavItem} the navitem to add
3633 addItem : function(cfg)
3635 var cn = new Roo.bootstrap.NavItem(cfg);
3637 cn.parentId = this.id;
3638 cn.onRender(this.el, null);
3642 * register a Navigation item
3643 * @param {Roo.bootstrap.NavItem} the navitem to add
3645 register : function(item)
3647 this.navItems.push( item);
3648 item.navId = this.navId;
3653 * clear all the Navigation item
3656 clearAll : function()
3659 this.el.dom.innerHTML = '';
3662 getNavItem: function(tabId)
3665 Roo.each(this.navItems, function(e) {
3666 if (e.tabId == tabId) {
3676 setActiveNext : function()
3678 var i = this.indexOfNav(this.getActive());
3679 if (i > this.navItems.length) {
3682 this.setActiveItem(this.navItems[i+1]);
3684 setActivePrev : function()
3686 var i = this.indexOfNav(this.getActive());
3690 this.setActiveItem(this.navItems[i-1]);
3692 clearWasActive : function(except) {
3693 Roo.each(this.navItems, function(e) {
3694 if (e.tabId != except.tabId && e.was_active) {
3695 e.was_active = false;
3702 getWasActive : function ()
3705 Roo.each(this.navItems, function(e) {
3720 Roo.apply(Roo.bootstrap.NavGroup, {
3724 * register a Navigation Group
3725 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3727 register : function(navgrp)
3729 this.groups[navgrp.navId] = navgrp;
3733 * fetch a Navigation Group based on the navigation ID
3734 * @param {string} the navgroup to add
3735 * @returns {Roo.bootstrap.NavGroup} the navgroup
3737 get: function(navId) {
3738 if (typeof(this.groups[navId]) == 'undefined') {
3740 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3742 return this.groups[navId] ;
3757 * @class Roo.bootstrap.NavItem
3758 * @extends Roo.bootstrap.Component
3759 * Bootstrap Navbar.NavItem class
3760 * @cfg {String} href link to
3761 * @cfg {String} html content of button
3762 * @cfg {String} badge text inside badge
3763 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3764 * @cfg {String} glyphicon name of glyphicon
3765 * @cfg {String} icon name of font awesome icon
3766 * @cfg {Boolean} active Is item active
3767 * @cfg {Boolean} disabled Is item disabled
3769 * @cfg {Boolean} preventDefault (true | false) default false
3770 * @cfg {String} tabId the tab that this item activates.
3771 * @cfg {String} tagtype (a|span) render as a href or span?
3772 * @cfg {Boolean} animateRef (true|false) link to element default false
3775 * Create a new Navbar Item
3776 * @param {Object} config The config object
3778 Roo.bootstrap.NavItem = function(config){
3779 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3784 * The raw click event for the entire grid.
3785 * @param {Roo.EventObject} e
3790 * Fires when the active item active state changes
3791 * @param {Roo.bootstrap.NavItem} this
3792 * @param {boolean} state the new state
3798 * Fires when scroll to element
3799 * @param {Roo.bootstrap.NavItem} this
3800 * @param {Object} options
3801 * @param {Roo.EventObject} e
3809 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3817 preventDefault : false,
3824 getAutoCreate : function(){
3832 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3834 if (this.disabled) {
3835 cfg.cls += ' disabled';
3838 if (this.href || this.html || this.glyphicon || this.icon) {
3842 href : this.href || "#",
3843 html: this.html || ''
3848 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3851 if(this.glyphicon) {
3852 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3857 cfg.cn[0].html += " <span class='caret'></span>";
3861 if (this.badge !== '') {
3863 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3871 initEvents: function()
3873 if (typeof (this.menu) != 'undefined') {
3874 this.menu.parentType = this.xtype;
3875 this.menu.triggerEl = this.el;
3876 this.menu = this.addxtype(Roo.apply({}, this.menu));
3879 this.el.select('a',true).on('click', this.onClick, this);
3881 if(this.tagtype == 'span'){
3882 this.el.select('span',true).on('click', this.onClick, this);
3885 // at this point parent should be available..
3886 this.parent().register(this);
3889 onClick : function(e)
3892 this.preventDefault ||
3899 if (this.disabled) {
3903 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3904 if (tg && tg.transition) {
3905 Roo.log("waiting for the transitionend");
3911 //Roo.log("fire event clicked");
3912 if(this.fireEvent('click', this, e) === false){
3916 if(this.tagtype == 'span'){
3920 //Roo.log(this.href);
3921 var ael = this.el.select('a',true).first();
3924 if(ael && this.animateRef && this.href.indexOf('#') > -1){
3925 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
3926 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
3927 return; // ignore... - it's a 'hash' to another page.
3931 this.scrollToElement(e);
3935 var p = this.parent();
3937 if (['tabs','pills'].indexOf(p.type)!==-1) {
3938 if (typeof(p.setActiveItem) !== 'undefined') {
3939 p.setActiveItem(this);
3944 isActive: function () {
3947 setActive : function(state, fire, is_was_active)
3949 if (this.active && !state & this.navId) {
3950 this.was_active = true;
3951 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3953 nv.clearWasActive(this);
3957 this.active = state;
3960 this.el.removeClass('active');
3961 } else if (!this.el.hasClass('active')) {
3962 this.el.addClass('active');
3965 this.fireEvent('changed', this, state);
3968 // show a panel if it's registered and related..
3970 if (!this.navId || !this.tabId || !state || is_was_active) {
3974 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3978 var pan = tg.getPanelByName(this.tabId);
3982 // if we can not flip to new panel - go back to old nav highlight..
3983 if (false == tg.showPanel(pan)) {
3984 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3986 var onav = nv.getWasActive();
3988 onav.setActive(true, false, true);
3997 // this should not be here...
3998 setDisabled : function(state)
4000 this.disabled = state;
4002 this.el.removeClass('disabled');
4003 } else if (!this.el.hasClass('disabled')) {
4004 this.el.addClass('disabled');
4010 * Fetch the element to display the tooltip on.
4011 * @return {Roo.Element} defaults to this.el
4013 tooltipEl : function()
4015 return this.el.select('' + this.tagtype + '', true).first();
4018 scrollToElement : function(e)
4020 var c = document.body;
4022 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4028 var o = target.calcOffsetsTo(c);
4035 this.fireEvent('scrollto', this, options, e);
4037 Roo.get(c).scrollTo('top', options.value, true);
4050 * <span> icon </span>
4051 * <span> text </span>
4052 * <span>badge </span>
4056 * @class Roo.bootstrap.NavSidebarItem
4057 * @extends Roo.bootstrap.NavItem
4058 * Bootstrap Navbar.NavSidebarItem class
4060 * Create a new Navbar Button
4061 * @param {Object} config The config object
4063 Roo.bootstrap.NavSidebarItem = function(config){
4064 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4069 * The raw click event for the entire grid.
4070 * @param {Roo.EventObject} e
4075 * Fires when the active item active state changes
4076 * @param {Roo.bootstrap.NavSidebarItem} this
4077 * @param {boolean} state the new state
4085 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4088 getAutoCreate : function(){
4093 href : this.href || '#',
4105 html : this.html || ''
4110 cfg.cls += ' active';
4114 if (this.glyphicon || this.icon) {
4115 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4116 a.cn.push({ tag : 'i', cls : c }) ;
4121 if (this.badge !== '') {
4122 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4126 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4127 a.cls += 'dropdown-toggle treeview' ;
4151 * @class Roo.bootstrap.Row
4152 * @extends Roo.bootstrap.Component
4153 * Bootstrap Row class (contains columns...)
4157 * @param {Object} config The config object
4160 Roo.bootstrap.Row = function(config){
4161 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4164 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4166 getAutoCreate : function(){
4185 * @class Roo.bootstrap.Element
4186 * @extends Roo.bootstrap.Component
4187 * Bootstrap Element class
4188 * @cfg {String} html contents of the element
4189 * @cfg {String} tag tag of the element
4190 * @cfg {String} cls class of the element
4191 * @cfg {Boolean} preventDefault (true|false) default false
4192 * @cfg {Boolean} clickable (true|false) default false
4195 * Create a new Element
4196 * @param {Object} config The config object
4199 Roo.bootstrap.Element = function(config){
4200 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4206 * When a element is chick
4207 * @param {Roo.bootstrap.Element} this
4208 * @param {Roo.EventObject} e
4214 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4219 preventDefault: false,
4222 getAutoCreate : function(){
4233 initEvents: function()
4235 Roo.bootstrap.Element.superclass.initEvents.call(this);
4238 this.el.on('click', this.onClick, this);
4243 onClick : function(e)
4245 if(this.preventDefault){
4249 this.fireEvent('click', this, e);
4252 getValue : function()
4254 return this.el.dom.innerHTML;
4257 setValue : function(value)
4259 this.el.dom.innerHTML = value;
4274 * @class Roo.bootstrap.Pagination
4275 * @extends Roo.bootstrap.Component
4276 * Bootstrap Pagination class
4277 * @cfg {String} size xs | sm | md | lg
4278 * @cfg {Boolean} inverse false | true
4281 * Create a new Pagination
4282 * @param {Object} config The config object
4285 Roo.bootstrap.Pagination = function(config){
4286 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4289 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4295 getAutoCreate : function(){
4301 cfg.cls += ' inverse';
4307 cfg.cls += " " + this.cls;
4325 * @class Roo.bootstrap.PaginationItem
4326 * @extends Roo.bootstrap.Component
4327 * Bootstrap PaginationItem class
4328 * @cfg {String} html text
4329 * @cfg {String} href the link
4330 * @cfg {Boolean} preventDefault (true | false) default true
4331 * @cfg {Boolean} active (true | false) default false
4332 * @cfg {Boolean} disabled default false
4336 * Create a new PaginationItem
4337 * @param {Object} config The config object
4341 Roo.bootstrap.PaginationItem = function(config){
4342 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4347 * The raw click event for the entire grid.
4348 * @param {Roo.EventObject} e
4354 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4358 preventDefault: true,
4363 getAutoCreate : function(){
4369 href : this.href ? this.href : '#',
4370 html : this.html ? this.html : ''
4380 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4384 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4390 initEvents: function() {
4392 this.el.on('click', this.onClick, this);
4395 onClick : function(e)
4397 Roo.log('PaginationItem on click ');
4398 if(this.preventDefault){
4406 this.fireEvent('click', this, e);
4422 * @class Roo.bootstrap.Slider
4423 * @extends Roo.bootstrap.Component
4424 * Bootstrap Slider class
4427 * Create a new Slider
4428 * @param {Object} config The config object
4431 Roo.bootstrap.Slider = function(config){
4432 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4435 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4437 getAutoCreate : function(){
4441 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4445 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4457 * Ext JS Library 1.1.1
4458 * Copyright(c) 2006-2007, Ext JS, LLC.
4460 * Originally Released Under LGPL - original licence link has changed is not relivant.
4463 * <script type="text/javascript">
4468 * @class Roo.grid.ColumnModel
4469 * @extends Roo.util.Observable
4470 * This is the default implementation of a ColumnModel used by the Grid. It defines
4471 * the columns in the grid.
4474 var colModel = new Roo.grid.ColumnModel([
4475 {header: "Ticker", width: 60, sortable: true, locked: true},
4476 {header: "Company Name", width: 150, sortable: true},
4477 {header: "Market Cap.", width: 100, sortable: true},
4478 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4479 {header: "Employees", width: 100, sortable: true, resizable: false}
4484 * The config options listed for this class are options which may appear in each
4485 * individual column definition.
4486 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4488 * @param {Object} config An Array of column config objects. See this class's
4489 * config objects for details.
4491 Roo.grid.ColumnModel = function(config){
4493 * The config passed into the constructor
4495 this.config = config;
4498 // if no id, create one
4499 // if the column does not have a dataIndex mapping,
4500 // map it to the order it is in the config
4501 for(var i = 0, len = config.length; i < len; i++){
4503 if(typeof c.dataIndex == "undefined"){
4506 if(typeof c.renderer == "string"){
4507 c.renderer = Roo.util.Format[c.renderer];
4509 if(typeof c.id == "undefined"){
4512 if(c.editor && c.editor.xtype){
4513 c.editor = Roo.factory(c.editor, Roo.grid);
4515 if(c.editor && c.editor.isFormField){
4516 c.editor = new Roo.grid.GridEditor(c.editor);
4518 this.lookup[c.id] = c;
4522 * The width of columns which have no width specified (defaults to 100)
4525 this.defaultWidth = 100;
4528 * Default sortable of columns which have no sortable specified (defaults to false)
4531 this.defaultSortable = false;
4535 * @event widthchange
4536 * Fires when the width of a column changes.
4537 * @param {ColumnModel} this
4538 * @param {Number} columnIndex The column index
4539 * @param {Number} newWidth The new width
4541 "widthchange": true,
4543 * @event headerchange
4544 * Fires when the text of a header changes.
4545 * @param {ColumnModel} this
4546 * @param {Number} columnIndex The column index
4547 * @param {Number} newText The new header text
4549 "headerchange": true,
4551 * @event hiddenchange
4552 * Fires when a column is hidden or "unhidden".
4553 * @param {ColumnModel} this
4554 * @param {Number} columnIndex The column index
4555 * @param {Boolean} hidden true if hidden, false otherwise
4557 "hiddenchange": true,
4559 * @event columnmoved
4560 * Fires when a column is moved.
4561 * @param {ColumnModel} this
4562 * @param {Number} oldIndex
4563 * @param {Number} newIndex
4565 "columnmoved" : true,
4567 * @event columlockchange
4568 * Fires when a column's locked state is changed
4569 * @param {ColumnModel} this
4570 * @param {Number} colIndex
4571 * @param {Boolean} locked true if locked
4573 "columnlockchange" : true
4575 Roo.grid.ColumnModel.superclass.constructor.call(this);
4577 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4579 * @cfg {String} header The header text to display in the Grid view.
4582 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4583 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4584 * specified, the column's index is used as an index into the Record's data Array.
4587 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4588 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4591 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4592 * Defaults to the value of the {@link #defaultSortable} property.
4593 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4596 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4599 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4602 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4605 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4608 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4609 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4610 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4611 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4614 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4617 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4620 * @cfg {String} cursor (Optional)
4623 * @cfg {String} tooltip (Optional)
4626 * Returns the id of the column at the specified index.
4627 * @param {Number} index The column index
4628 * @return {String} the id
4630 getColumnId : function(index){
4631 return this.config[index].id;
4635 * Returns the column for a specified id.
4636 * @param {String} id The column id
4637 * @return {Object} the column
4639 getColumnById : function(id){
4640 return this.lookup[id];
4645 * Returns the column for a specified dataIndex.
4646 * @param {String} dataIndex The column dataIndex
4647 * @return {Object|Boolean} the column or false if not found
4649 getColumnByDataIndex: function(dataIndex){
4650 var index = this.findColumnIndex(dataIndex);
4651 return index > -1 ? this.config[index] : false;
4655 * Returns the index for a specified column id.
4656 * @param {String} id The column id
4657 * @return {Number} the index, or -1 if not found
4659 getIndexById : function(id){
4660 for(var i = 0, len = this.config.length; i < len; i++){
4661 if(this.config[i].id == id){
4669 * Returns the index for a specified column dataIndex.
4670 * @param {String} dataIndex The column dataIndex
4671 * @return {Number} the index, or -1 if not found
4674 findColumnIndex : function(dataIndex){
4675 for(var i = 0, len = this.config.length; i < len; i++){
4676 if(this.config[i].dataIndex == dataIndex){
4684 moveColumn : function(oldIndex, newIndex){
4685 var c = this.config[oldIndex];
4686 this.config.splice(oldIndex, 1);
4687 this.config.splice(newIndex, 0, c);
4688 this.dataMap = null;
4689 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4692 isLocked : function(colIndex){
4693 return this.config[colIndex].locked === true;
4696 setLocked : function(colIndex, value, suppressEvent){
4697 if(this.isLocked(colIndex) == value){
4700 this.config[colIndex].locked = value;
4702 this.fireEvent("columnlockchange", this, colIndex, value);
4706 getTotalLockedWidth : function(){
4708 for(var i = 0; i < this.config.length; i++){
4709 if(this.isLocked(i) && !this.isHidden(i)){
4710 this.totalWidth += this.getColumnWidth(i);
4716 getLockedCount : function(){
4717 for(var i = 0, len = this.config.length; i < len; i++){
4718 if(!this.isLocked(i)){
4725 * Returns the number of columns.
4728 getColumnCount : function(visibleOnly){
4729 if(visibleOnly === true){
4731 for(var i = 0, len = this.config.length; i < len; i++){
4732 if(!this.isHidden(i)){
4738 return this.config.length;
4742 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4743 * @param {Function} fn
4744 * @param {Object} scope (optional)
4745 * @return {Array} result
4747 getColumnsBy : function(fn, scope){
4749 for(var i = 0, len = this.config.length; i < len; i++){
4750 var c = this.config[i];
4751 if(fn.call(scope||this, c, i) === true){
4759 * Returns true if the specified column is sortable.
4760 * @param {Number} col The column index
4763 isSortable : function(col){
4764 if(typeof this.config[col].sortable == "undefined"){
4765 return this.defaultSortable;
4767 return this.config[col].sortable;
4771 * Returns the rendering (formatting) function defined for the column.
4772 * @param {Number} col The column index.
4773 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4775 getRenderer : function(col){
4776 if(!this.config[col].renderer){
4777 return Roo.grid.ColumnModel.defaultRenderer;
4779 return this.config[col].renderer;
4783 * Sets the rendering (formatting) function for a column.
4784 * @param {Number} col The column index
4785 * @param {Function} fn The function to use to process the cell's raw data
4786 * to return HTML markup for the grid view. The render function is called with
4787 * the following parameters:<ul>
4788 * <li>Data value.</li>
4789 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4790 * <li>css A CSS style string to apply to the table cell.</li>
4791 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4792 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4793 * <li>Row index</li>
4794 * <li>Column index</li>
4795 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4797 setRenderer : function(col, fn){
4798 this.config[col].renderer = fn;
4802 * Returns the width for the specified column.
4803 * @param {Number} col The column index
4806 getColumnWidth : function(col){
4807 return this.config[col].width * 1 || this.defaultWidth;
4811 * Sets the width for a column.
4812 * @param {Number} col The column index
4813 * @param {Number} width The new width
4815 setColumnWidth : function(col, width, suppressEvent){
4816 this.config[col].width = width;
4817 this.totalWidth = null;
4819 this.fireEvent("widthchange", this, col, width);
4824 * Returns the total width of all columns.
4825 * @param {Boolean} includeHidden True to include hidden column widths
4828 getTotalWidth : function(includeHidden){
4829 if(!this.totalWidth){
4830 this.totalWidth = 0;
4831 for(var i = 0, len = this.config.length; i < len; i++){
4832 if(includeHidden || !this.isHidden(i)){
4833 this.totalWidth += this.getColumnWidth(i);
4837 return this.totalWidth;
4841 * Returns the header for the specified column.
4842 * @param {Number} col The column index
4845 getColumnHeader : function(col){
4846 return this.config[col].header;
4850 * Sets the header for a column.
4851 * @param {Number} col The column index
4852 * @param {String} header The new header
4854 setColumnHeader : function(col, header){
4855 this.config[col].header = header;
4856 this.fireEvent("headerchange", this, col, header);
4860 * Returns the tooltip for the specified column.
4861 * @param {Number} col The column index
4864 getColumnTooltip : function(col){
4865 return this.config[col].tooltip;
4868 * Sets the tooltip for a column.
4869 * @param {Number} col The column index
4870 * @param {String} tooltip The new tooltip
4872 setColumnTooltip : function(col, tooltip){
4873 this.config[col].tooltip = tooltip;
4877 * Returns the dataIndex for the specified column.
4878 * @param {Number} col The column index
4881 getDataIndex : function(col){
4882 return this.config[col].dataIndex;
4886 * Sets the dataIndex for a column.
4887 * @param {Number} col The column index
4888 * @param {Number} dataIndex The new dataIndex
4890 setDataIndex : function(col, dataIndex){
4891 this.config[col].dataIndex = dataIndex;
4897 * Returns true if the cell is editable.
4898 * @param {Number} colIndex The column index
4899 * @param {Number} rowIndex The row index
4902 isCellEditable : function(colIndex, rowIndex){
4903 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4907 * Returns the editor defined for the cell/column.
4908 * return false or null to disable editing.
4909 * @param {Number} colIndex The column index
4910 * @param {Number} rowIndex The row index
4913 getCellEditor : function(colIndex, rowIndex){
4914 return this.config[colIndex].editor;
4918 * Sets if a column is editable.
4919 * @param {Number} col The column index
4920 * @param {Boolean} editable True if the column is editable
4922 setEditable : function(col, editable){
4923 this.config[col].editable = editable;
4928 * Returns true if the column is hidden.
4929 * @param {Number} colIndex The column index
4932 isHidden : function(colIndex){
4933 return this.config[colIndex].hidden;
4938 * Returns true if the column width cannot be changed
4940 isFixed : function(colIndex){
4941 return this.config[colIndex].fixed;
4945 * Returns true if the column can be resized
4948 isResizable : function(colIndex){
4949 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4952 * Sets if a column is hidden.
4953 * @param {Number} colIndex The column index
4954 * @param {Boolean} hidden True if the column is hidden
4956 setHidden : function(colIndex, hidden){
4957 this.config[colIndex].hidden = hidden;
4958 this.totalWidth = null;
4959 this.fireEvent("hiddenchange", this, colIndex, hidden);
4963 * Sets the editor for a column.
4964 * @param {Number} col The column index
4965 * @param {Object} editor The editor object
4967 setEditor : function(col, editor){
4968 this.config[col].editor = editor;
4972 Roo.grid.ColumnModel.defaultRenderer = function(value){
4973 if(typeof value == "string" && value.length < 1){
4979 // Alias for backwards compatibility
4980 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4983 * Ext JS Library 1.1.1
4984 * Copyright(c) 2006-2007, Ext JS, LLC.
4986 * Originally Released Under LGPL - original licence link has changed is not relivant.
4989 * <script type="text/javascript">
4993 * @class Roo.LoadMask
4994 * A simple utility class for generically masking elements while loading data. If the element being masked has
4995 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4996 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4997 * element's UpdateManager load indicator and will be destroyed after the initial load.
4999 * Create a new LoadMask
5000 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5001 * @param {Object} config The config object
5003 Roo.LoadMask = function(el, config){
5004 this.el = Roo.get(el);
5005 Roo.apply(this, config);
5007 this.store.on('beforeload', this.onBeforeLoad, this);
5008 this.store.on('load', this.onLoad, this);
5009 this.store.on('loadexception', this.onLoadException, this);
5010 this.removeMask = false;
5012 var um = this.el.getUpdateManager();
5013 um.showLoadIndicator = false; // disable the default indicator
5014 um.on('beforeupdate', this.onBeforeLoad, this);
5015 um.on('update', this.onLoad, this);
5016 um.on('failure', this.onLoad, this);
5017 this.removeMask = true;
5021 Roo.LoadMask.prototype = {
5023 * @cfg {Boolean} removeMask
5024 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5025 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5029 * The text to display in a centered loading message box (defaults to 'Loading...')
5033 * @cfg {String} msgCls
5034 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5036 msgCls : 'x-mask-loading',
5039 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5045 * Disables the mask to prevent it from being displayed
5047 disable : function(){
5048 this.disabled = true;
5052 * Enables the mask so that it can be displayed
5054 enable : function(){
5055 this.disabled = false;
5058 onLoadException : function()
5062 if (typeof(arguments[3]) != 'undefined') {
5063 Roo.MessageBox.alert("Error loading",arguments[3]);
5067 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5068 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5077 this.el.unmask(this.removeMask);
5082 this.el.unmask(this.removeMask);
5086 onBeforeLoad : function(){
5088 this.el.mask(this.msg, this.msgCls);
5093 destroy : function(){
5095 this.store.un('beforeload', this.onBeforeLoad, this);
5096 this.store.un('load', this.onLoad, this);
5097 this.store.un('loadexception', this.onLoadException, this);
5099 var um = this.el.getUpdateManager();
5100 um.un('beforeupdate', this.onBeforeLoad, this);
5101 um.un('update', this.onLoad, this);
5102 um.un('failure', this.onLoad, this);
5113 * @class Roo.bootstrap.Table
5114 * @extends Roo.bootstrap.Component
5115 * Bootstrap Table class
5116 * @cfg {String} cls table class
5117 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5118 * @cfg {String} bgcolor Specifies the background color for a table
5119 * @cfg {Number} border Specifies whether the table cells should have borders or not
5120 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5121 * @cfg {Number} cellspacing Specifies the space between cells
5122 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5123 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5124 * @cfg {String} sortable Specifies that the table should be sortable
5125 * @cfg {String} summary Specifies a summary of the content of a table
5126 * @cfg {Number} width Specifies the width of a table
5127 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5129 * @cfg {boolean} striped Should the rows be alternative striped
5130 * @cfg {boolean} bordered Add borders to the table
5131 * @cfg {boolean} hover Add hover highlighting
5132 * @cfg {boolean} condensed Format condensed
5133 * @cfg {boolean} responsive Format condensed
5134 * @cfg {Boolean} loadMask (true|false) default false
5135 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5136 * @cfg {Boolean} thead (true|false) generate thead, default true
5137 * @cfg {Boolean} RowSelection (true|false) default false
5138 * @cfg {Boolean} CellSelection (true|false) default false
5139 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5143 * Create a new Table
5144 * @param {Object} config The config object
5147 Roo.bootstrap.Table = function(config){
5148 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5151 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5152 this.sm = this.selModel;
5153 this.sm.xmodule = this.xmodule || false;
5155 if (this.cm && typeof(this.cm.config) == 'undefined') {
5156 this.colModel = new Roo.grid.ColumnModel(this.cm);
5157 this.cm = this.colModel;
5158 this.cm.xmodule = this.xmodule || false;
5161 this.store= Roo.factory(this.store, Roo.data);
5162 this.ds = this.store;
5163 this.ds.xmodule = this.xmodule || false;
5166 if (this.footer && this.store) {
5167 this.footer.dataSource = this.ds;
5168 this.footer = Roo.factory(this.footer);
5175 * Fires when a cell is clicked
5176 * @param {Roo.bootstrap.Table} this
5177 * @param {Roo.Element} el
5178 * @param {Number} rowIndex
5179 * @param {Number} columnIndex
5180 * @param {Roo.EventObject} e
5184 * @event celldblclick
5185 * Fires when a cell is double clicked
5186 * @param {Roo.bootstrap.Table} this
5187 * @param {Roo.Element} el
5188 * @param {Number} rowIndex
5189 * @param {Number} columnIndex
5190 * @param {Roo.EventObject} e
5192 "celldblclick" : true,
5195 * Fires when a row is clicked
5196 * @param {Roo.bootstrap.Table} this
5197 * @param {Roo.Element} el
5198 * @param {Number} rowIndex
5199 * @param {Roo.EventObject} e
5203 * @event rowdblclick
5204 * Fires when a row is double clicked
5205 * @param {Roo.bootstrap.Table} this
5206 * @param {Roo.Element} el
5207 * @param {Number} rowIndex
5208 * @param {Roo.EventObject} e
5210 "rowdblclick" : true,
5213 * Fires when a mouseover occur
5214 * @param {Roo.bootstrap.Table} this
5215 * @param {Roo.Element} el
5216 * @param {Number} rowIndex
5217 * @param {Number} columnIndex
5218 * @param {Roo.EventObject} e
5223 * Fires when a mouseout occur
5224 * @param {Roo.bootstrap.Table} this
5225 * @param {Roo.Element} el
5226 * @param {Number} rowIndex
5227 * @param {Number} columnIndex
5228 * @param {Roo.EventObject} e
5233 * Fires when a row is rendered, so you can change add a style to it.
5234 * @param {Roo.bootstrap.Table} this
5235 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5239 * @event rowsrendered
5240 * Fires when all the rows have been rendered
5241 * @param {Roo.bootstrap.Table} this
5243 'rowsrendered' : true
5248 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5272 RowSelection : false,
5273 CellSelection : false,
5276 // Roo.Element - the tbody
5279 getAutoCreate : function(){
5280 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5289 cfg.cls += ' table-striped';
5293 cfg.cls += ' table-hover';
5295 if (this.bordered) {
5296 cfg.cls += ' table-bordered';
5298 if (this.condensed) {
5299 cfg.cls += ' table-condensed';
5301 if (this.responsive) {
5302 cfg.cls += ' table-responsive';
5306 cfg.cls+= ' ' +this.cls;
5309 // this lot should be simplifed...
5312 cfg.align=this.align;
5315 cfg.bgcolor=this.bgcolor;
5318 cfg.border=this.border;
5320 if (this.cellpadding) {
5321 cfg.cellpadding=this.cellpadding;
5323 if (this.cellspacing) {
5324 cfg.cellspacing=this.cellspacing;
5327 cfg.frame=this.frame;
5330 cfg.rules=this.rules;
5332 if (this.sortable) {
5333 cfg.sortable=this.sortable;
5336 cfg.summary=this.summary;
5339 cfg.width=this.width;
5342 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5345 if(this.store || this.cm){
5347 cfg.cn.push(this.renderHeader());
5350 cfg.cn.push(this.renderBody());
5353 cfg.cn.push(this.renderFooter());
5356 cfg.cls+= ' TableGrid';
5359 return { cn : [ cfg ] };
5362 initEvents : function()
5364 if(!this.store || !this.cm){
5368 //Roo.log('initEvents with ds!!!!');
5370 this.mainBody = this.el.select('tbody', true).first();
5375 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5376 e.on('click', _this.sort, _this);
5379 this.el.on("click", this.onClick, this);
5380 this.el.on("dblclick", this.onDblClick, this);
5382 // why is this done????? = it breaks dialogs??
5383 //this.parent().el.setStyle('position', 'relative');
5387 this.footer.parentId = this.id;
5388 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5391 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5393 this.store.on('load', this.onLoad, this);
5394 this.store.on('beforeload', this.onBeforeLoad, this);
5395 this.store.on('update', this.onUpdate, this);
5396 this.store.on('add', this.onAdd, this);
5400 onMouseover : function(e, el)
5402 var cell = Roo.get(el);
5408 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5409 cell = cell.findParent('td', false, true);
5412 var row = cell.findParent('tr', false, true);
5413 var cellIndex = cell.dom.cellIndex;
5414 var rowIndex = row.dom.rowIndex - 1; // start from 0
5416 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5420 onMouseout : function(e, el)
5422 var cell = Roo.get(el);
5428 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5429 cell = cell.findParent('td', false, true);
5432 var row = cell.findParent('tr', false, true);
5433 var cellIndex = cell.dom.cellIndex;
5434 var rowIndex = row.dom.rowIndex - 1; // start from 0
5436 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5440 onClick : function(e, el)
5442 var cell = Roo.get(el);
5444 if(!cell || (!this.CellSelection && !this.RowSelection)){
5448 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5449 cell = cell.findParent('td', false, true);
5452 if(!cell || typeof(cell) == 'undefined'){
5456 var row = cell.findParent('tr', false, true);
5458 if(!row || typeof(row) == 'undefined'){
5462 var cellIndex = cell.dom.cellIndex;
5463 var rowIndex = this.getRowIndex(row);
5465 if(this.CellSelection){
5466 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5469 if(this.RowSelection){
5470 this.fireEvent('rowclick', this, row, rowIndex, e);
5476 onDblClick : function(e,el)
5478 var cell = Roo.get(el);
5480 if(!cell || (!this.CellSelection && !this.RowSelection)){
5484 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5485 cell = cell.findParent('td', false, true);
5488 if(!cell || typeof(cell) == 'undefined'){
5492 var row = cell.findParent('tr', false, true);
5494 if(!row || typeof(row) == 'undefined'){
5498 var cellIndex = cell.dom.cellIndex;
5499 var rowIndex = this.getRowIndex(row);
5501 if(this.CellSelection){
5502 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5505 if(this.RowSelection){
5506 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5510 sort : function(e,el)
5512 var col = Roo.get(el);
5514 if(!col.hasClass('sortable')){
5518 var sort = col.attr('sort');
5521 if(col.hasClass('glyphicon-arrow-up')){
5525 this.store.sortInfo = {field : sort, direction : dir};
5528 Roo.log("calling footer first");
5529 this.footer.onClick('first');
5532 this.store.load({ params : { start : 0 } });
5536 renderHeader : function()
5545 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5547 var config = cm.config[i];
5552 html: cm.getColumnHeader(i)
5555 if(typeof(config.tooltip) != 'undefined'){
5556 c.tooltip = config.tooltip;
5559 if(typeof(config.colspan) != 'undefined'){
5560 c.colspan = config.colspan;
5563 if(typeof(config.hidden) != 'undefined' && config.hidden){
5564 c.style += ' display:none;';
5567 if(typeof(config.dataIndex) != 'undefined'){
5568 c.sort = config.dataIndex;
5571 if(typeof(config.sortable) != 'undefined' && config.sortable){
5575 if(typeof(config.align) != 'undefined' && config.align.length){
5576 c.style += ' text-align:' + config.align + ';';
5579 if(typeof(config.width) != 'undefined'){
5580 c.style += ' width:' + config.width + 'px;';
5583 if(typeof(config.cls) != 'undefined'){
5584 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5593 renderBody : function()
5603 colspan : this.cm.getColumnCount()
5613 renderFooter : function()
5623 colspan : this.cm.getColumnCount()
5637 Roo.log('ds onload');
5642 var ds = this.store;
5644 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5645 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5647 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5648 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5651 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5652 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5656 var tbody = this.mainBody;
5658 if(ds.getCount() > 0){
5659 ds.data.each(function(d,rowIndex){
5660 var row = this.renderRow(cm, ds, rowIndex);
5662 tbody.createChild(row);
5666 if(row.cellObjects.length){
5667 Roo.each(row.cellObjects, function(r){
5668 _this.renderCellObject(r);
5675 Roo.each(this.el.select('tbody td', true).elements, function(e){
5676 e.on('mouseover', _this.onMouseover, _this);
5679 Roo.each(this.el.select('tbody td', true).elements, function(e){
5680 e.on('mouseout', _this.onMouseout, _this);
5682 this.fireEvent('rowsrendered', this);
5683 //if(this.loadMask){
5684 // this.maskEl.hide();
5689 onUpdate : function(ds,record)
5691 this.refreshRow(record);
5694 onRemove : function(ds, record, index, isUpdate){
5695 if(isUpdate !== true){
5696 this.fireEvent("beforerowremoved", this, index, record);
5698 var bt = this.mainBody.dom;
5700 var rows = this.el.select('tbody > tr', true).elements;
5702 if(typeof(rows[index]) != 'undefined'){
5703 bt.removeChild(rows[index].dom);
5706 // if(bt.rows[index]){
5707 // bt.removeChild(bt.rows[index]);
5710 if(isUpdate !== true){
5711 //this.stripeRows(index);
5712 //this.syncRowHeights(index, index);
5714 this.fireEvent("rowremoved", this, index, record);
5718 onAdd : function(ds, records, rowIndex)
5720 //Roo.log('on Add called');
5721 // - note this does not handle multiple adding very well..
5722 var bt = this.mainBody.dom;
5723 for (var i =0 ; i < records.length;i++) {
5724 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5725 //Roo.log(records[i]);
5726 //Roo.log(this.store.getAt(rowIndex+i));
5727 this.insertRow(this.store, rowIndex + i, false);
5734 refreshRow : function(record){
5735 var ds = this.store, index;
5736 if(typeof record == 'number'){
5738 record = ds.getAt(index);
5740 index = ds.indexOf(record);
5742 this.insertRow(ds, index, true);
5743 this.onRemove(ds, record, index+1, true);
5744 //this.syncRowHeights(index, index);
5746 this.fireEvent("rowupdated", this, index, record);
5749 insertRow : function(dm, rowIndex, isUpdate){
5752 this.fireEvent("beforerowsinserted", this, rowIndex);
5754 //var s = this.getScrollState();
5755 var row = this.renderRow(this.cm, this.store, rowIndex);
5756 // insert before rowIndex..
5757 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5761 if(row.cellObjects.length){
5762 Roo.each(row.cellObjects, function(r){
5763 _this.renderCellObject(r);
5768 this.fireEvent("rowsinserted", this, rowIndex);
5769 //this.syncRowHeights(firstRow, lastRow);
5770 //this.stripeRows(firstRow);
5777 getRowDom : function(rowIndex)
5779 var rows = this.el.select('tbody > tr', true).elements;
5781 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5784 // returns the object tree for a tr..
5787 renderRow : function(cm, ds, rowIndex)
5790 var d = ds.getAt(rowIndex);
5797 var cellObjects = [];
5799 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5800 var config = cm.config[i];
5802 var renderer = cm.getRenderer(i);
5806 if(typeof(renderer) !== 'undefined'){
5807 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5809 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5810 // and are rendered into the cells after the row is rendered - using the id for the element.
5812 if(typeof(value) === 'object'){
5822 rowIndex : rowIndex,
5827 this.fireEvent('rowclass', this, rowcfg);
5831 cls : rowcfg.rowClass,
5833 html: (typeof(value) === 'object') ? '' : value
5840 if(typeof(config.colspan) != 'undefined'){
5841 td.colspan = config.colspan;
5844 if(typeof(config.hidden) != 'undefined' && config.hidden){
5845 td.style += ' display:none;';
5848 if(typeof(config.align) != 'undefined' && config.align.length){
5849 td.style += ' text-align:' + config.align + ';';
5852 if(typeof(config.width) != 'undefined'){
5853 td.style += ' width:' + config.width + 'px;';
5856 if(typeof(config.cursor) != 'undefined'){
5857 td.style += ' cursor:' + config.cursor + ';';
5860 if(typeof(config.cls) != 'undefined'){
5861 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
5868 row.cellObjects = cellObjects;
5876 onBeforeLoad : function()
5878 //Roo.log('ds onBeforeLoad');
5882 //if(this.loadMask){
5883 // this.maskEl.show();
5891 this.el.select('tbody', true).first().dom.innerHTML = '';
5894 * Show or hide a row.
5895 * @param {Number} rowIndex to show or hide
5896 * @param {Boolean} state hide
5898 setRowVisibility : function(rowIndex, state)
5900 var bt = this.mainBody.dom;
5902 var rows = this.el.select('tbody > tr', true).elements;
5904 if(typeof(rows[rowIndex]) == 'undefined'){
5907 rows[rowIndex].dom.style.display = state ? '' : 'none';
5911 getSelectionModel : function(){
5913 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5915 return this.selModel;
5918 * Render the Roo.bootstrap object from renderder
5920 renderCellObject : function(r)
5924 var t = r.cfg.render(r.container);
5927 Roo.each(r.cfg.cn, function(c){
5929 container: t.getChildContainer(),
5932 _this.renderCellObject(child);
5937 getRowIndex : function(row)
5941 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5964 * @class Roo.bootstrap.TableCell
5965 * @extends Roo.bootstrap.Component
5966 * Bootstrap TableCell class
5967 * @cfg {String} html cell contain text
5968 * @cfg {String} cls cell class
5969 * @cfg {String} tag cell tag (td|th) default td
5970 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5971 * @cfg {String} align Aligns the content in a cell
5972 * @cfg {String} axis Categorizes cells
5973 * @cfg {String} bgcolor Specifies the background color of a cell
5974 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5975 * @cfg {Number} colspan Specifies the number of columns a cell should span
5976 * @cfg {String} headers Specifies one or more header cells a cell is related to
5977 * @cfg {Number} height Sets the height of a cell
5978 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5979 * @cfg {Number} rowspan Sets the number of rows a cell should span
5980 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5981 * @cfg {String} valign Vertical aligns the content in a cell
5982 * @cfg {Number} width Specifies the width of a cell
5985 * Create a new TableCell
5986 * @param {Object} config The config object
5989 Roo.bootstrap.TableCell = function(config){
5990 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5993 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6013 getAutoCreate : function(){
6014 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6034 cfg.align=this.align
6040 cfg.bgcolor=this.bgcolor
6043 cfg.charoff=this.charoff
6046 cfg.colspan=this.colspan
6049 cfg.headers=this.headers
6052 cfg.height=this.height
6055 cfg.nowrap=this.nowrap
6058 cfg.rowspan=this.rowspan
6061 cfg.scope=this.scope
6064 cfg.valign=this.valign
6067 cfg.width=this.width
6086 * @class Roo.bootstrap.TableRow
6087 * @extends Roo.bootstrap.Component
6088 * Bootstrap TableRow class
6089 * @cfg {String} cls row class
6090 * @cfg {String} align Aligns the content in a table row
6091 * @cfg {String} bgcolor Specifies a background color for a table row
6092 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6093 * @cfg {String} valign Vertical aligns the content in a table row
6096 * Create a new TableRow
6097 * @param {Object} config The config object
6100 Roo.bootstrap.TableRow = function(config){
6101 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6104 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6112 getAutoCreate : function(){
6113 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6123 cfg.align = this.align;
6126 cfg.bgcolor = this.bgcolor;
6129 cfg.charoff = this.charoff;
6132 cfg.valign = this.valign;
6150 * @class Roo.bootstrap.TableBody
6151 * @extends Roo.bootstrap.Component
6152 * Bootstrap TableBody class
6153 * @cfg {String} cls element class
6154 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6155 * @cfg {String} align Aligns the content inside the element
6156 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6157 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6160 * Create a new TableBody
6161 * @param {Object} config The config object
6164 Roo.bootstrap.TableBody = function(config){
6165 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6168 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6176 getAutoCreate : function(){
6177 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6191 cfg.align = this.align;
6194 cfg.charoff = this.charoff;
6197 cfg.valign = this.valign;
6204 // initEvents : function()
6211 // this.store = Roo.factory(this.store, Roo.data);
6212 // this.store.on('load', this.onLoad, this);
6214 // this.store.load();
6218 // onLoad: function ()
6220 // this.fireEvent('load', this);
6230 * Ext JS Library 1.1.1
6231 * Copyright(c) 2006-2007, Ext JS, LLC.
6233 * Originally Released Under LGPL - original licence link has changed is not relivant.
6236 * <script type="text/javascript">
6239 // as we use this in bootstrap.
6240 Roo.namespace('Roo.form');
6242 * @class Roo.form.Action
6243 * Internal Class used to handle form actions
6245 * @param {Roo.form.BasicForm} el The form element or its id
6246 * @param {Object} config Configuration options
6251 // define the action interface
6252 Roo.form.Action = function(form, options){
6254 this.options = options || {};
6257 * Client Validation Failed
6260 Roo.form.Action.CLIENT_INVALID = 'client';
6262 * Server Validation Failed
6265 Roo.form.Action.SERVER_INVALID = 'server';
6267 * Connect to Server Failed
6270 Roo.form.Action.CONNECT_FAILURE = 'connect';
6272 * Reading Data from Server Failed
6275 Roo.form.Action.LOAD_FAILURE = 'load';
6277 Roo.form.Action.prototype = {
6279 failureType : undefined,
6280 response : undefined,
6284 run : function(options){
6289 success : function(response){
6294 handleResponse : function(response){
6298 // default connection failure
6299 failure : function(response){
6301 this.response = response;
6302 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6303 this.form.afterAction(this, false);
6306 processResponse : function(response){
6307 this.response = response;
6308 if(!response.responseText){
6311 this.result = this.handleResponse(response);
6315 // utility functions used internally
6316 getUrl : function(appendParams){
6317 var url = this.options.url || this.form.url || this.form.el.dom.action;
6319 var p = this.getParams();
6321 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6327 getMethod : function(){
6328 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6331 getParams : function(){
6332 var bp = this.form.baseParams;
6333 var p = this.options.params;
6335 if(typeof p == "object"){
6336 p = Roo.urlEncode(Roo.applyIf(p, bp));
6337 }else if(typeof p == 'string' && bp){
6338 p += '&' + Roo.urlEncode(bp);
6341 p = Roo.urlEncode(bp);
6346 createCallback : function(){
6348 success: this.success,
6349 failure: this.failure,
6351 timeout: (this.form.timeout*1000),
6352 upload: this.form.fileUpload ? this.success : undefined
6357 Roo.form.Action.Submit = function(form, options){
6358 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6361 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6364 haveProgress : false,
6365 uploadComplete : false,
6367 // uploadProgress indicator.
6368 uploadProgress : function()
6370 if (!this.form.progressUrl) {
6374 if (!this.haveProgress) {
6375 Roo.MessageBox.progress("Uploading", "Uploading");
6377 if (this.uploadComplete) {
6378 Roo.MessageBox.hide();
6382 this.haveProgress = true;
6384 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6386 var c = new Roo.data.Connection();
6388 url : this.form.progressUrl,
6393 success : function(req){
6394 //console.log(data);
6398 rdata = Roo.decode(req.responseText)
6400 Roo.log("Invalid data from server..");
6404 if (!rdata || !rdata.success) {
6406 Roo.MessageBox.alert(Roo.encode(rdata));
6409 var data = rdata.data;
6411 if (this.uploadComplete) {
6412 Roo.MessageBox.hide();
6417 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6418 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6421 this.uploadProgress.defer(2000,this);
6424 failure: function(data) {
6425 Roo.log('progress url failed ');
6436 // run get Values on the form, so it syncs any secondary forms.
6437 this.form.getValues();
6439 var o = this.options;
6440 var method = this.getMethod();
6441 var isPost = method == 'POST';
6442 if(o.clientValidation === false || this.form.isValid()){
6444 if (this.form.progressUrl) {
6445 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6446 (new Date() * 1) + '' + Math.random());
6451 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6452 form:this.form.el.dom,
6453 url:this.getUrl(!isPost),
6455 params:isPost ? this.getParams() : null,
6456 isUpload: this.form.fileUpload
6459 this.uploadProgress();
6461 }else if (o.clientValidation !== false){ // client validation failed
6462 this.failureType = Roo.form.Action.CLIENT_INVALID;
6463 this.form.afterAction(this, false);
6467 success : function(response)
6469 this.uploadComplete= true;
6470 if (this.haveProgress) {
6471 Roo.MessageBox.hide();
6475 var result = this.processResponse(response);
6476 if(result === true || result.success){
6477 this.form.afterAction(this, true);
6481 this.form.markInvalid(result.errors);
6482 this.failureType = Roo.form.Action.SERVER_INVALID;
6484 this.form.afterAction(this, false);
6486 failure : function(response)
6488 this.uploadComplete= true;
6489 if (this.haveProgress) {
6490 Roo.MessageBox.hide();
6493 this.response = response;
6494 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6495 this.form.afterAction(this, false);
6498 handleResponse : function(response){
6499 if(this.form.errorReader){
6500 var rs = this.form.errorReader.read(response);
6503 for(var i = 0, len = rs.records.length; i < len; i++) {
6504 var r = rs.records[i];
6508 if(errors.length < 1){
6512 success : rs.success,
6518 ret = Roo.decode(response.responseText);
6522 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6532 Roo.form.Action.Load = function(form, options){
6533 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6534 this.reader = this.form.reader;
6537 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6542 Roo.Ajax.request(Roo.apply(
6543 this.createCallback(), {
6544 method:this.getMethod(),
6545 url:this.getUrl(false),
6546 params:this.getParams()
6550 success : function(response){
6552 var result = this.processResponse(response);
6553 if(result === true || !result.success || !result.data){
6554 this.failureType = Roo.form.Action.LOAD_FAILURE;
6555 this.form.afterAction(this, false);
6558 this.form.clearInvalid();
6559 this.form.setValues(result.data);
6560 this.form.afterAction(this, true);
6563 handleResponse : function(response){
6564 if(this.form.reader){
6565 var rs = this.form.reader.read(response);
6566 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6568 success : rs.success,
6572 return Roo.decode(response.responseText);
6576 Roo.form.Action.ACTION_TYPES = {
6577 'load' : Roo.form.Action.Load,
6578 'submit' : Roo.form.Action.Submit
6587 * @class Roo.bootstrap.Form
6588 * @extends Roo.bootstrap.Component
6589 * Bootstrap Form class
6590 * @cfg {String} method GET | POST (default POST)
6591 * @cfg {String} labelAlign top | left (default top)
6592 * @cfg {String} align left | right - for navbars
6593 * @cfg {Boolean} loadMask load mask when submit (default true)
6598 * @param {Object} config The config object
6602 Roo.bootstrap.Form = function(config){
6603 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6606 * @event clientvalidation
6607 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6608 * @param {Form} this
6609 * @param {Boolean} valid true if the form has passed client-side validation
6611 clientvalidation: true,
6613 * @event beforeaction
6614 * Fires before any action is performed. Return false to cancel the action.
6615 * @param {Form} this
6616 * @param {Action} action The action to be performed
6620 * @event actionfailed
6621 * Fires when an action fails.
6622 * @param {Form} this
6623 * @param {Action} action The action that failed
6625 actionfailed : true,
6627 * @event actioncomplete
6628 * Fires when an action is completed.
6629 * @param {Form} this
6630 * @param {Action} action The action that completed
6632 actioncomplete : true
6637 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6640 * @cfg {String} method
6641 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6646 * The URL to use for form actions if one isn't supplied in the action options.
6649 * @cfg {Boolean} fileUpload
6650 * Set to true if this form is a file upload.
6654 * @cfg {Object} baseParams
6655 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6659 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6663 * @cfg {Sting} align (left|right) for navbar forms
6668 activeAction : null,
6671 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6672 * element by passing it or its id or mask the form itself by passing in true.
6675 waitMsgTarget : false,
6679 getAutoCreate : function(){
6683 method : this.method || 'POST',
6684 id : this.id || Roo.id(),
6687 if (this.parent().xtype.match(/^Nav/)) {
6688 cfg.cls = 'navbar-form navbar-' + this.align;
6692 if (this.labelAlign == 'left' ) {
6693 cfg.cls += ' form-horizontal';
6699 initEvents : function()
6701 this.el.on('submit', this.onSubmit, this);
6702 // this was added as random key presses on the form where triggering form submit.
6703 this.el.on('keypress', function(e) {
6704 if (e.getCharCode() != 13) {
6707 // we might need to allow it for textareas.. and some other items.
6708 // check e.getTarget().
6710 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6714 Roo.log("keypress blocked");
6722 onSubmit : function(e){
6727 * Returns true if client-side validation on the form is successful.
6730 isValid : function(){
6731 var items = this.getItems();
6733 items.each(function(f){
6742 * Returns true if any fields in this form have changed since their original load.
6745 isDirty : function(){
6747 var items = this.getItems();
6748 items.each(function(f){
6758 * Performs a predefined action (submit or load) or custom actions you define on this form.
6759 * @param {String} actionName The name of the action type
6760 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6761 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6762 * accept other config options):
6764 Property Type Description
6765 ---------------- --------------- ----------------------------------------------------------------------------------
6766 url String The url for the action (defaults to the form's url)
6767 method String The form method to use (defaults to the form's method, or POST if not defined)
6768 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6769 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6770 validate the form on the client (defaults to false)
6772 * @return {BasicForm} this
6774 doAction : function(action, options){
6775 if(typeof action == 'string'){
6776 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6778 if(this.fireEvent('beforeaction', this, action) !== false){
6779 this.beforeAction(action);
6780 action.run.defer(100, action);
6786 beforeAction : function(action){
6787 var o = action.options;
6790 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6792 // not really supported yet.. ??
6794 //if(this.waitMsgTarget === true){
6795 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6796 //}else if(this.waitMsgTarget){
6797 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6798 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6800 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6806 afterAction : function(action, success){
6807 this.activeAction = null;
6808 var o = action.options;
6810 //if(this.waitMsgTarget === true){
6812 //}else if(this.waitMsgTarget){
6813 // this.waitMsgTarget.unmask();
6815 // Roo.MessageBox.updateProgress(1);
6816 // Roo.MessageBox.hide();
6823 Roo.callback(o.success, o.scope, [this, action]);
6824 this.fireEvent('actioncomplete', this, action);
6828 // failure condition..
6829 // we have a scenario where updates need confirming.
6830 // eg. if a locking scenario exists..
6831 // we look for { errors : { needs_confirm : true }} in the response.
6833 (typeof(action.result) != 'undefined') &&
6834 (typeof(action.result.errors) != 'undefined') &&
6835 (typeof(action.result.errors.needs_confirm) != 'undefined')
6838 Roo.log("not supported yet");
6841 Roo.MessageBox.confirm(
6842 "Change requires confirmation",
6843 action.result.errorMsg,
6848 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6858 Roo.callback(o.failure, o.scope, [this, action]);
6859 // show an error message if no failed handler is set..
6860 if (!this.hasListener('actionfailed')) {
6861 Roo.log("need to add dialog support");
6863 Roo.MessageBox.alert("Error",
6864 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6865 action.result.errorMsg :
6866 "Saving Failed, please check your entries or try again"
6871 this.fireEvent('actionfailed', this, action);
6876 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6877 * @param {String} id The value to search for
6880 findField : function(id){
6881 var items = this.getItems();
6882 var field = items.get(id);
6884 items.each(function(f){
6885 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6892 return field || null;
6895 * Mark fields in this form invalid in bulk.
6896 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6897 * @return {BasicForm} this
6899 markInvalid : function(errors){
6900 if(errors instanceof Array){
6901 for(var i = 0, len = errors.length; i < len; i++){
6902 var fieldError = errors[i];
6903 var f = this.findField(fieldError.id);
6905 f.markInvalid(fieldError.msg);
6911 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6912 field.markInvalid(errors[id]);
6916 //Roo.each(this.childForms || [], function (f) {
6917 // f.markInvalid(errors);
6924 * Set values for fields in this form in bulk.
6925 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6926 * @return {BasicForm} this
6928 setValues : function(values){
6929 if(values instanceof Array){ // array of objects
6930 for(var i = 0, len = values.length; i < len; i++){
6932 var f = this.findField(v.id);
6934 f.setValue(v.value);
6935 if(this.trackResetOnLoad){
6936 f.originalValue = f.getValue();
6940 }else{ // object hash
6943 if(typeof values[id] != 'function' && (field = this.findField(id))){
6945 if (field.setFromData &&
6947 field.displayField &&
6948 // combos' with local stores can
6949 // be queried via setValue()
6950 // to set their value..
6951 (field.store && !field.store.isLocal)
6955 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6956 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6957 field.setFromData(sd);
6960 field.setValue(values[id]);
6964 if(this.trackResetOnLoad){
6965 field.originalValue = field.getValue();
6971 //Roo.each(this.childForms || [], function (f) {
6972 // f.setValues(values);
6979 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6980 * they are returned as an array.
6981 * @param {Boolean} asString
6984 getValues : function(asString){
6985 //if (this.childForms) {
6986 // copy values from the child forms
6987 // Roo.each(this.childForms, function (f) {
6988 // this.setValues(f.getValues());
6994 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6995 if(asString === true){
6998 return Roo.urlDecode(fs);
7002 * Returns the fields in this form as an object with key/value pairs.
7003 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7006 getFieldValues : function(with_hidden)
7008 var items = this.getItems();
7010 items.each(function(f){
7014 var v = f.getValue();
7015 if (f.inputType =='radio') {
7016 if (typeof(ret[f.getName()]) == 'undefined') {
7017 ret[f.getName()] = ''; // empty..
7020 if (!f.el.dom.checked) {
7028 // not sure if this supported any more..
7029 if ((typeof(v) == 'object') && f.getRawValue) {
7030 v = f.getRawValue() ; // dates..
7032 // combo boxes where name != hiddenName...
7033 if (f.name != f.getName()) {
7034 ret[f.name] = f.getRawValue();
7036 ret[f.getName()] = v;
7043 * Clears all invalid messages in this form.
7044 * @return {BasicForm} this
7046 clearInvalid : function(){
7047 var items = this.getItems();
7049 items.each(function(f){
7060 * @return {BasicForm} this
7063 var items = this.getItems();
7064 items.each(function(f){
7068 Roo.each(this.childForms || [], function (f) {
7075 getItems : function()
7077 var r=new Roo.util.MixedCollection(false, function(o){
7078 return o.id || (o.id = Roo.id());
7080 var iter = function(el) {
7087 Roo.each(el.items,function(e) {
7107 * Ext JS Library 1.1.1
7108 * Copyright(c) 2006-2007, Ext JS, LLC.
7110 * Originally Released Under LGPL - original licence link has changed is not relivant.
7113 * <script type="text/javascript">
7116 * @class Roo.form.VTypes
7117 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7120 Roo.form.VTypes = function(){
7121 // closure these in so they are only created once.
7122 var alpha = /^[a-zA-Z_]+$/;
7123 var alphanum = /^[a-zA-Z0-9_]+$/;
7124 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7125 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7127 // All these messages and functions are configurable
7130 * The function used to validate email addresses
7131 * @param {String} value The email address
7133 'email' : function(v){
7134 return email.test(v);
7137 * The error text to display when the email validation function returns false
7140 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7142 * The keystroke filter mask to be applied on email input
7145 'emailMask' : /[a-z0-9_\.\-@]/i,
7148 * The function used to validate URLs
7149 * @param {String} value The URL
7151 'url' : function(v){
7155 * The error text to display when the url validation function returns false
7158 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7161 * The function used to validate alpha values
7162 * @param {String} value The value
7164 'alpha' : function(v){
7165 return alpha.test(v);
7168 * The error text to display when the alpha validation function returns false
7171 'alphaText' : 'This field should only contain letters and _',
7173 * The keystroke filter mask to be applied on alpha input
7176 'alphaMask' : /[a-z_]/i,
7179 * The function used to validate alphanumeric values
7180 * @param {String} value The value
7182 'alphanum' : function(v){
7183 return alphanum.test(v);
7186 * The error text to display when the alphanumeric validation function returns false
7189 'alphanumText' : 'This field should only contain letters, numbers and _',
7191 * The keystroke filter mask to be applied on alphanumeric input
7194 'alphanumMask' : /[a-z0-9_]/i
7204 * @class Roo.bootstrap.Input
7205 * @extends Roo.bootstrap.Component
7206 * Bootstrap Input class
7207 * @cfg {Boolean} disabled is it disabled
7208 * @cfg {String} fieldLabel - the label associated
7209 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7210 * @cfg {String} name name of the input
7211 * @cfg {string} fieldLabel - the label associated
7212 * @cfg {string} inputType - input / file submit ...
7213 * @cfg {string} placeholder - placeholder to put in text.
7214 * @cfg {string} before - input group add on before
7215 * @cfg {string} after - input group add on after
7216 * @cfg {string} size - (lg|sm) or leave empty..
7217 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7218 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7219 * @cfg {Number} md colspan out of 12 for computer-sized screens
7220 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7221 * @cfg {string} value default value of the input
7222 * @cfg {Number} labelWidth set the width of label (0-12)
7223 * @cfg {String} labelAlign (top|left)
7224 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7225 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7227 * @cfg {String} align (left|center|right) Default left
7232 * Create a new Input
7233 * @param {Object} config The config object
7236 Roo.bootstrap.Input = function(config){
7237 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7242 * Fires when this field receives input focus.
7243 * @param {Roo.form.Field} this
7248 * Fires when this field loses input focus.
7249 * @param {Roo.form.Field} this
7254 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7255 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7256 * @param {Roo.form.Field} this
7257 * @param {Roo.EventObject} e The event object
7262 * Fires just before the field blurs if the field value has changed.
7263 * @param {Roo.form.Field} this
7264 * @param {Mixed} newValue The new value
7265 * @param {Mixed} oldValue The original value
7270 * Fires after the field has been marked as invalid.
7271 * @param {Roo.form.Field} this
7272 * @param {String} msg The validation message
7277 * Fires after the field has been validated with no errors.
7278 * @param {Roo.form.Field} this
7283 * Fires after the key up
7284 * @param {Roo.form.Field} this
7285 * @param {Roo.EventObject} e The event Object
7291 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7293 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7294 automatic validation (defaults to "keyup").
7296 validationEvent : "keyup",
7298 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7300 validateOnBlur : true,
7302 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7304 validationDelay : 250,
7306 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7308 focusClass : "x-form-focus", // not needed???
7312 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7314 invalidClass : "has-warning",
7317 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7319 validClass : "has-success",
7322 * @cfg {Boolean} hasFeedback (true|false) default true
7327 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7329 invalidFeedbackClass : "glyphicon-warning-sign",
7332 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7334 validFeedbackClass : "glyphicon-ok",
7337 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7339 selectOnFocus : false,
7342 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7346 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7351 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7353 disableKeyFilter : false,
7356 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7360 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7364 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7366 blankText : "This field is required",
7369 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7373 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7375 maxLength : Number.MAX_VALUE,
7377 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7379 minLengthText : "The minimum length for this field is {0}",
7381 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7383 maxLengthText : "The maximum length for this field is {0}",
7387 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7388 * If available, this function will be called only after the basic validators all return true, and will be passed the
7389 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7393 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7394 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7395 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7399 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7403 autocomplete: false,
7422 formatedValue : false,
7424 parentLabelAlign : function()
7427 while (parent.parent()) {
7428 parent = parent.parent();
7429 if (typeof(parent.labelAlign) !='undefined') {
7430 return parent.labelAlign;
7437 getAutoCreate : function(){
7439 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7445 if(this.inputType != 'hidden'){
7446 cfg.cls = 'form-group' //input-group
7452 type : this.inputType,
7454 cls : 'form-control',
7455 placeholder : this.placeholder || '',
7456 autocomplete : this.autocomplete || 'new-password'
7461 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7464 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7465 input.maxLength = this.maxLength;
7468 if (this.disabled) {
7469 input.disabled=true;
7472 if (this.readOnly) {
7473 input.readonly=true;
7477 input.name = this.name;
7480 input.cls += ' input-' + this.size;
7483 ['xs','sm','md','lg'].map(function(size){
7484 if (settings[size]) {
7485 cfg.cls += ' col-' + size + '-' + settings[size];
7489 var inputblock = input;
7493 cls: 'glyphicon form-control-feedback'
7496 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7499 cls : 'has-feedback',
7507 if (this.before || this.after) {
7510 cls : 'input-group',
7514 if (this.before && typeof(this.before) == 'string') {
7516 inputblock.cn.push({
7518 cls : 'roo-input-before input-group-addon',
7522 if (this.before && typeof(this.before) == 'object') {
7523 this.before = Roo.factory(this.before);
7524 Roo.log(this.before);
7525 inputblock.cn.push({
7527 cls : 'roo-input-before input-group-' +
7528 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7532 inputblock.cn.push(input);
7534 if (this.after && typeof(this.after) == 'string') {
7535 inputblock.cn.push({
7537 cls : 'roo-input-after input-group-addon',
7541 if (this.after && typeof(this.after) == 'object') {
7542 this.after = Roo.factory(this.after);
7543 Roo.log(this.after);
7544 inputblock.cn.push({
7546 cls : 'roo-input-after input-group-' +
7547 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7551 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7552 inputblock.cls += ' has-feedback';
7553 inputblock.cn.push(feedback);
7557 if (align ==='left' && this.fieldLabel.length) {
7558 Roo.log("left and has label");
7564 cls : 'control-label col-sm-' + this.labelWidth,
7565 html : this.fieldLabel
7569 cls : "col-sm-" + (12 - this.labelWidth),
7576 } else if ( this.fieldLabel.length) {
7582 //cls : 'input-group-addon',
7583 html : this.fieldLabel
7593 Roo.log(" no label && no align");
7602 Roo.log('input-parentType: ' + this.parentType);
7604 if (this.parentType === 'Navbar' && this.parent().bar) {
7605 cfg.cls += ' navbar-form';
7613 * return the real input element.
7615 inputEl: function ()
7617 return this.el.select('input.form-control',true).first();
7620 tooltipEl : function()
7622 return this.inputEl();
7625 setDisabled : function(v)
7627 var i = this.inputEl().dom;
7629 i.removeAttribute('disabled');
7633 i.setAttribute('disabled','true');
7635 initEvents : function()
7638 this.inputEl().on("keydown" , this.fireKey, this);
7639 this.inputEl().on("focus", this.onFocus, this);
7640 this.inputEl().on("blur", this.onBlur, this);
7642 this.inputEl().relayEvent('keyup', this);
7644 // reference to original value for reset
7645 this.originalValue = this.getValue();
7646 //Roo.form.TextField.superclass.initEvents.call(this);
7647 if(this.validationEvent == 'keyup'){
7648 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7649 this.inputEl().on('keyup', this.filterValidation, this);
7651 else if(this.validationEvent !== false){
7652 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7655 if(this.selectOnFocus){
7656 this.on("focus", this.preFocus, this);
7659 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7660 this.inputEl().on("keypress", this.filterKeys, this);
7663 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7664 this.el.on("click", this.autoSize, this);
7667 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7668 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7671 if (typeof(this.before) == 'object') {
7672 this.before.render(this.el.select('.roo-input-before',true).first());
7674 if (typeof(this.after) == 'object') {
7675 this.after.render(this.el.select('.roo-input-after',true).first());
7680 filterValidation : function(e){
7681 if(!e.isNavKeyPress()){
7682 this.validationTask.delay(this.validationDelay);
7686 * Validates the field value
7687 * @return {Boolean} True if the value is valid, else false
7689 validate : function(){
7690 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7691 if(this.disabled || this.validateValue(this.getRawValue())){
7702 * Validates a value according to the field's validation rules and marks the field as invalid
7703 * if the validation fails
7704 * @param {Mixed} value The value to validate
7705 * @return {Boolean} True if the value is valid, else false
7707 validateValue : function(value){
7708 if(value.length < 1) { // if it's blank
7709 if(this.allowBlank){
7715 if(value.length < this.minLength){
7718 if(value.length > this.maxLength){
7722 var vt = Roo.form.VTypes;
7723 if(!vt[this.vtype](value, this)){
7727 if(typeof this.validator == "function"){
7728 var msg = this.validator(value);
7734 if(this.regex && !this.regex.test(value)){
7744 fireKey : function(e){
7745 //Roo.log('field ' + e.getKey());
7746 if(e.isNavKeyPress()){
7747 this.fireEvent("specialkey", this, e);
7750 focus : function (selectText){
7752 this.inputEl().focus();
7753 if(selectText === true){
7754 this.inputEl().dom.select();
7760 onFocus : function(){
7761 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7762 // this.el.addClass(this.focusClass);
7765 this.hasFocus = true;
7766 this.startValue = this.getValue();
7767 this.fireEvent("focus", this);
7771 beforeBlur : Roo.emptyFn,
7775 onBlur : function(){
7777 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7778 //this.el.removeClass(this.focusClass);
7780 this.hasFocus = false;
7781 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7784 var v = this.getValue();
7785 if(String(v) !== String(this.startValue)){
7786 this.fireEvent('change', this, v, this.startValue);
7788 this.fireEvent("blur", this);
7792 * Resets the current field value to the originally loaded value and clears any validation messages
7795 this.setValue(this.originalValue);
7799 * Returns the name of the field
7800 * @return {Mixed} name The name field
7802 getName: function(){
7806 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7807 * @return {Mixed} value The field value
7809 getValue : function(){
7811 var v = this.inputEl().getValue();
7816 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7817 * @return {Mixed} value The field value
7819 getRawValue : function(){
7820 var v = this.inputEl().getValue();
7826 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7827 * @param {Mixed} value The value to set
7829 setRawValue : function(v){
7830 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7833 selectText : function(start, end){
7834 var v = this.getRawValue();
7836 start = start === undefined ? 0 : start;
7837 end = end === undefined ? v.length : end;
7838 var d = this.inputEl().dom;
7839 if(d.setSelectionRange){
7840 d.setSelectionRange(start, end);
7841 }else if(d.createTextRange){
7842 var range = d.createTextRange();
7843 range.moveStart("character", start);
7844 range.moveEnd("character", v.length-end);
7851 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7852 * @param {Mixed} value The value to set
7854 setValue : function(v){
7857 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7863 processValue : function(value){
7864 if(this.stripCharsRe){
7865 var newValue = value.replace(this.stripCharsRe, '');
7866 if(newValue !== value){
7867 this.setRawValue(newValue);
7874 preFocus : function(){
7876 if(this.selectOnFocus){
7877 this.inputEl().dom.select();
7880 filterKeys : function(e){
7882 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7885 var c = e.getCharCode(), cc = String.fromCharCode(c);
7886 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7889 if(!this.maskRe.test(cc)){
7894 * Clear any invalid styles/messages for this field
7896 clearInvalid : function(){
7898 if(!this.el || this.preventMark){ // not rendered
7901 this.el.removeClass(this.invalidClass);
7903 this.fireEvent('valid', this);
7907 * Mark this field as valid
7909 markValid : function(){
7910 if(!this.el || this.preventMark){ // not rendered
7914 this.el.removeClass([this.invalidClass, this.validClass]);
7916 if(this.disabled || this.allowBlank){
7920 this.el.addClass(this.validClass);
7922 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7924 var feedback = this.el.select('.form-control-feedback', true).first();
7927 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7928 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7933 this.fireEvent('valid', this);
7937 * Mark this field as invalid
7938 * @param {String} msg The validation message
7940 markInvalid : function(msg){
7941 if(!this.el || this.preventMark){ // not rendered
7945 this.el.removeClass([this.invalidClass, this.validClass]);
7947 if(this.disabled || this.allowBlank){
7951 this.el.addClass(this.invalidClass);
7953 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7955 var feedback = this.el.select('.form-control-feedback', true).first();
7958 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7960 if(this.getValue().length){
7961 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7968 this.fireEvent('invalid', this, msg);
7971 SafariOnKeyDown : function(event)
7973 // this is a workaround for a password hang bug on chrome/ webkit.
7975 var isSelectAll = false;
7977 if(this.inputEl().dom.selectionEnd > 0){
7978 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7980 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7981 event.preventDefault();
7986 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7988 event.preventDefault();
7989 // this is very hacky as keydown always get's upper case.
7991 var cc = String.fromCharCode(event.getCharCode());
7992 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7996 adjustWidth : function(tag, w){
7997 tag = tag.toLowerCase();
7998 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7999 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8003 if(tag == 'textarea'){
8006 }else if(Roo.isOpera){
8010 if(tag == 'textarea'){
8029 * @class Roo.bootstrap.TextArea
8030 * @extends Roo.bootstrap.Input
8031 * Bootstrap TextArea class
8032 * @cfg {Number} cols Specifies the visible width of a text area
8033 * @cfg {Number} rows Specifies the visible number of lines in a text area
8034 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8035 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8036 * @cfg {string} html text
8039 * Create a new TextArea
8040 * @param {Object} config The config object
8043 Roo.bootstrap.TextArea = function(config){
8044 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8048 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8058 getAutoCreate : function(){
8060 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8071 value : this.value || '',
8072 html: this.html || '',
8073 cls : 'form-control',
8074 placeholder : this.placeholder || ''
8078 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8079 input.maxLength = this.maxLength;
8083 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8087 input.cols = this.cols;
8090 if (this.readOnly) {
8091 input.readonly = true;
8095 input.name = this.name;
8099 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8103 ['xs','sm','md','lg'].map(function(size){
8104 if (settings[size]) {
8105 cfg.cls += ' col-' + size + '-' + settings[size];
8109 var inputblock = input;
8111 if(this.hasFeedback && !this.allowBlank){
8115 cls: 'glyphicon form-control-feedback'
8119 cls : 'has-feedback',
8128 if (this.before || this.after) {
8131 cls : 'input-group',
8135 inputblock.cn.push({
8137 cls : 'input-group-addon',
8142 inputblock.cn.push(input);
8144 if(this.hasFeedback && !this.allowBlank){
8145 inputblock.cls += ' has-feedback';
8146 inputblock.cn.push(feedback);
8150 inputblock.cn.push({
8152 cls : 'input-group-addon',
8159 if (align ==='left' && this.fieldLabel.length) {
8160 Roo.log("left and has label");
8166 cls : 'control-label col-sm-' + this.labelWidth,
8167 html : this.fieldLabel
8171 cls : "col-sm-" + (12 - this.labelWidth),
8178 } else if ( this.fieldLabel.length) {
8184 //cls : 'input-group-addon',
8185 html : this.fieldLabel
8195 Roo.log(" no label && no align");
8205 if (this.disabled) {
8206 input.disabled=true;
8213 * return the real textarea element.
8215 inputEl: function ()
8217 return this.el.select('textarea.form-control',true).first();
8225 * trigger field - base class for combo..
8230 * @class Roo.bootstrap.TriggerField
8231 * @extends Roo.bootstrap.Input
8232 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8233 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8234 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8235 * for which you can provide a custom implementation. For example:
8237 var trigger = new Roo.bootstrap.TriggerField();
8238 trigger.onTriggerClick = myTriggerFn;
8239 trigger.applyTo('my-field');
8242 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8243 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8244 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8245 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8246 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8249 * Create a new TriggerField.
8250 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8251 * to the base TextField)
8253 Roo.bootstrap.TriggerField = function(config){
8254 this.mimicing = false;
8255 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8258 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8260 * @cfg {String} triggerClass A CSS class to apply to the trigger
8263 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8267 /** @cfg {Boolean} grow @hide */
8268 /** @cfg {Number} growMin @hide */
8269 /** @cfg {Number} growMax @hide */
8275 autoSize: Roo.emptyFn,
8282 actionMode : 'wrap',
8287 getAutoCreate : function(){
8289 var align = this.labelAlign || this.parentLabelAlign();
8294 cls: 'form-group' //input-group
8301 type : this.inputType,
8302 cls : 'form-control',
8303 autocomplete: 'new-password',
8304 placeholder : this.placeholder || ''
8308 input.name = this.name;
8311 input.cls += ' input-' + this.size;
8314 if (this.disabled) {
8315 input.disabled=true;
8318 var inputblock = input;
8320 if(this.hasFeedback && !this.allowBlank){
8324 cls: 'glyphicon form-control-feedback'
8328 cls : 'has-feedback',
8336 if (this.before || this.after) {
8339 cls : 'input-group',
8343 inputblock.cn.push({
8345 cls : 'input-group-addon',
8350 inputblock.cn.push(input);
8352 if(this.hasFeedback && !this.allowBlank){
8353 inputblock.cls += ' has-feedback';
8354 inputblock.cn.push(feedback);
8358 inputblock.cn.push({
8360 cls : 'input-group-addon',
8373 cls: 'form-hidden-field'
8381 Roo.log('multiple');
8389 cls: 'form-hidden-field'
8393 cls: 'select2-choices',
8397 cls: 'select2-search-field',
8410 cls: 'select2-container input-group',
8415 // cls: 'typeahead typeahead-long dropdown-menu',
8416 // style: 'display:none'
8421 if(!this.multiple && this.showToggleBtn){
8427 if (this.caret != false) {
8430 cls: 'fa fa-' + this.caret
8437 cls : 'input-group-addon btn dropdown-toggle',
8442 cls: 'combobox-clear',
8456 combobox.cls += ' select2-container-multi';
8459 if (align ==='left' && this.fieldLabel.length) {
8461 Roo.log("left and has label");
8467 cls : 'control-label col-sm-' + this.labelWidth,
8468 html : this.fieldLabel
8472 cls : "col-sm-" + (12 - this.labelWidth),
8479 } else if ( this.fieldLabel.length) {
8485 //cls : 'input-group-addon',
8486 html : this.fieldLabel
8496 Roo.log(" no label && no align");
8503 ['xs','sm','md','lg'].map(function(size){
8504 if (settings[size]) {
8505 cfg.cls += ' col-' + size + '-' + settings[size];
8516 onResize : function(w, h){
8517 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8518 // if(typeof w == 'number'){
8519 // var x = w - this.trigger.getWidth();
8520 // this.inputEl().setWidth(this.adjustWidth('input', x));
8521 // this.trigger.setStyle('left', x+'px');
8526 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8529 getResizeEl : function(){
8530 return this.inputEl();
8534 getPositionEl : function(){
8535 return this.inputEl();
8539 alignErrorIcon : function(){
8540 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8544 initEvents : function(){
8548 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8549 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8550 if(!this.multiple && this.showToggleBtn){
8551 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8552 if(this.hideTrigger){
8553 this.trigger.setDisplayed(false);
8555 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8559 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8562 //this.trigger.addClassOnOver('x-form-trigger-over');
8563 //this.trigger.addClassOnClick('x-form-trigger-click');
8566 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8570 createList : function()
8572 this.list = Roo.get(document.body).createChild({
8574 cls: 'typeahead typeahead-long dropdown-menu',
8575 style: 'display:none'
8578 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8583 initTrigger : function(){
8588 onDestroy : function(){
8590 this.trigger.removeAllListeners();
8591 // this.trigger.remove();
8594 // this.wrap.remove();
8596 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8600 onFocus : function(){
8601 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8604 this.wrap.addClass('x-trigger-wrap-focus');
8605 this.mimicing = true;
8606 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8607 if(this.monitorTab){
8608 this.el.on("keydown", this.checkTab, this);
8615 checkTab : function(e){
8616 if(e.getKey() == e.TAB){
8622 onBlur : function(){
8627 mimicBlur : function(e, t){
8629 if(!this.wrap.contains(t) && this.validateBlur()){
8636 triggerBlur : function(){
8637 this.mimicing = false;
8638 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8639 if(this.monitorTab){
8640 this.el.un("keydown", this.checkTab, this);
8642 //this.wrap.removeClass('x-trigger-wrap-focus');
8643 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8647 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8648 validateBlur : function(e, t){
8653 onDisable : function(){
8654 this.inputEl().dom.disabled = true;
8655 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8657 // this.wrap.addClass('x-item-disabled');
8662 onEnable : function(){
8663 this.inputEl().dom.disabled = false;
8664 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8666 // this.el.removeClass('x-item-disabled');
8671 onShow : function(){
8672 var ae = this.getActionEl();
8675 ae.dom.style.display = '';
8676 ae.dom.style.visibility = 'visible';
8682 onHide : function(){
8683 var ae = this.getActionEl();
8684 ae.dom.style.display = 'none';
8688 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8689 * by an implementing function.
8691 * @param {EventObject} e
8693 onTriggerClick : Roo.emptyFn
8697 * Ext JS Library 1.1.1
8698 * Copyright(c) 2006-2007, Ext JS, LLC.
8700 * Originally Released Under LGPL - original licence link has changed is not relivant.
8703 * <script type="text/javascript">
8708 * @class Roo.data.SortTypes
8710 * Defines the default sorting (casting?) comparison functions used when sorting data.
8712 Roo.data.SortTypes = {
8714 * Default sort that does nothing
8715 * @param {Mixed} s The value being converted
8716 * @return {Mixed} The comparison value
8723 * The regular expression used to strip tags
8727 stripTagsRE : /<\/?[^>]+>/gi,
8730 * Strips all HTML tags to sort on text only
8731 * @param {Mixed} s The value being converted
8732 * @return {String} The comparison value
8734 asText : function(s){
8735 return String(s).replace(this.stripTagsRE, "");
8739 * Strips all HTML tags to sort on text only - Case insensitive
8740 * @param {Mixed} s The value being converted
8741 * @return {String} The comparison value
8743 asUCText : function(s){
8744 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8748 * Case insensitive string
8749 * @param {Mixed} s The value being converted
8750 * @return {String} The comparison value
8752 asUCString : function(s) {
8753 return String(s).toUpperCase();
8758 * @param {Mixed} s The value being converted
8759 * @return {Number} The comparison value
8761 asDate : function(s) {
8765 if(s instanceof Date){
8768 return Date.parse(String(s));
8773 * @param {Mixed} s The value being converted
8774 * @return {Float} The comparison value
8776 asFloat : function(s) {
8777 var val = parseFloat(String(s).replace(/,/g, ""));
8778 if(isNaN(val)) val = 0;
8784 * @param {Mixed} s The value being converted
8785 * @return {Number} The comparison value
8787 asInt : function(s) {
8788 var val = parseInt(String(s).replace(/,/g, ""));
8789 if(isNaN(val)) val = 0;
8794 * Ext JS Library 1.1.1
8795 * Copyright(c) 2006-2007, Ext JS, LLC.
8797 * Originally Released Under LGPL - original licence link has changed is not relivant.
8800 * <script type="text/javascript">
8804 * @class Roo.data.Record
8805 * Instances of this class encapsulate both record <em>definition</em> information, and record
8806 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8807 * to access Records cached in an {@link Roo.data.Store} object.<br>
8809 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8810 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8813 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8815 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8816 * {@link #create}. The parameters are the same.
8817 * @param {Array} data An associative Array of data values keyed by the field name.
8818 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8819 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8820 * not specified an integer id is generated.
8822 Roo.data.Record = function(data, id){
8823 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8828 * Generate a constructor for a specific record layout.
8829 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8830 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8831 * Each field definition object may contain the following properties: <ul>
8832 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8833 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8834 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8835 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8836 * is being used, then this is a string containing the javascript expression to reference the data relative to
8837 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8838 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8839 * this may be omitted.</p></li>
8840 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8841 * <ul><li>auto (Default, implies no conversion)</li>
8846 * <li>date</li></ul></p></li>
8847 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8848 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8849 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8850 * by the Reader into an object that will be stored in the Record. It is passed the
8851 * following parameters:<ul>
8852 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8854 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8856 * <br>usage:<br><pre><code>
8857 var TopicRecord = Roo.data.Record.create(
8858 {name: 'title', mapping: 'topic_title'},
8859 {name: 'author', mapping: 'username'},
8860 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8861 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8862 {name: 'lastPoster', mapping: 'user2'},
8863 {name: 'excerpt', mapping: 'post_text'}
8866 var myNewRecord = new TopicRecord({
8867 title: 'Do my job please',
8870 lastPost: new Date(),
8871 lastPoster: 'Animal',
8872 excerpt: 'No way dude!'
8874 myStore.add(myNewRecord);
8879 Roo.data.Record.create = function(o){
8881 f.superclass.constructor.apply(this, arguments);
8883 Roo.extend(f, Roo.data.Record);
8884 var p = f.prototype;
8885 p.fields = new Roo.util.MixedCollection(false, function(field){
8888 for(var i = 0, len = o.length; i < len; i++){
8889 p.fields.add(new Roo.data.Field(o[i]));
8891 f.getField = function(name){
8892 return p.fields.get(name);
8897 Roo.data.Record.AUTO_ID = 1000;
8898 Roo.data.Record.EDIT = 'edit';
8899 Roo.data.Record.REJECT = 'reject';
8900 Roo.data.Record.COMMIT = 'commit';
8902 Roo.data.Record.prototype = {
8904 * Readonly flag - true if this record has been modified.
8913 join : function(store){
8918 * Set the named field to the specified value.
8919 * @param {String} name The name of the field to set.
8920 * @param {Object} value The value to set the field to.
8922 set : function(name, value){
8923 if(this.data[name] == value){
8930 if(typeof this.modified[name] == 'undefined'){
8931 this.modified[name] = this.data[name];
8933 this.data[name] = value;
8934 if(!this.editing && this.store){
8935 this.store.afterEdit(this);
8940 * Get the value of the named field.
8941 * @param {String} name The name of the field to get the value of.
8942 * @return {Object} The value of the field.
8944 get : function(name){
8945 return this.data[name];
8949 beginEdit : function(){
8950 this.editing = true;
8955 cancelEdit : function(){
8956 this.editing = false;
8957 delete this.modified;
8961 endEdit : function(){
8962 this.editing = false;
8963 if(this.dirty && this.store){
8964 this.store.afterEdit(this);
8969 * Usually called by the {@link Roo.data.Store} which owns the Record.
8970 * Rejects all changes made to the Record since either creation, or the last commit operation.
8971 * Modified fields are reverted to their original values.
8973 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8974 * of reject operations.
8976 reject : function(){
8977 var m = this.modified;
8979 if(typeof m[n] != "function"){
8980 this.data[n] = m[n];
8984 delete this.modified;
8985 this.editing = false;
8987 this.store.afterReject(this);
8992 * Usually called by the {@link Roo.data.Store} which owns the Record.
8993 * Commits all changes made to the Record since either creation, or the last commit operation.
8995 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8996 * of commit operations.
8998 commit : function(){
9000 delete this.modified;
9001 this.editing = false;
9003 this.store.afterCommit(this);
9008 hasError : function(){
9009 return this.error != null;
9013 clearError : function(){
9018 * Creates a copy of this record.
9019 * @param {String} id (optional) A new record id if you don't want to use this record's id
9022 copy : function(newId) {
9023 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9027 * Ext JS Library 1.1.1
9028 * Copyright(c) 2006-2007, Ext JS, LLC.
9030 * Originally Released Under LGPL - original licence link has changed is not relivant.
9033 * <script type="text/javascript">
9039 * @class Roo.data.Store
9040 * @extends Roo.util.Observable
9041 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9042 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9044 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
9045 * has no knowledge of the format of the data returned by the Proxy.<br>
9047 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9048 * instances from the data object. These records are cached and made available through accessor functions.
9050 * Creates a new Store.
9051 * @param {Object} config A config object containing the objects needed for the Store to access data,
9052 * and read the data into Records.
9054 Roo.data.Store = function(config){
9055 this.data = new Roo.util.MixedCollection(false);
9056 this.data.getKey = function(o){
9059 this.baseParams = {};
9066 "multisort" : "_multisort"
9069 if(config && config.data){
9070 this.inlineData = config.data;
9074 Roo.apply(this, config);
9076 if(this.reader){ // reader passed
9077 this.reader = Roo.factory(this.reader, Roo.data);
9078 this.reader.xmodule = this.xmodule || false;
9079 if(!this.recordType){
9080 this.recordType = this.reader.recordType;
9082 if(this.reader.onMetaChange){
9083 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9087 if(this.recordType){
9088 this.fields = this.recordType.prototype.fields;
9094 * @event datachanged
9095 * Fires when the data cache has changed, and a widget which is using this Store
9096 * as a Record cache should refresh its view.
9097 * @param {Store} this
9102 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9103 * @param {Store} this
9104 * @param {Object} meta The JSON metadata
9109 * Fires when Records have been added to the Store
9110 * @param {Store} this
9111 * @param {Roo.data.Record[]} records The array of Records added
9112 * @param {Number} index The index at which the record(s) were added
9117 * Fires when a Record has been removed from the Store
9118 * @param {Store} this
9119 * @param {Roo.data.Record} record The Record that was removed
9120 * @param {Number} index The index at which the record was removed
9125 * Fires when a Record has been updated
9126 * @param {Store} this
9127 * @param {Roo.data.Record} record The Record that was updated
9128 * @param {String} operation The update operation being performed. Value may be one of:
9130 Roo.data.Record.EDIT
9131 Roo.data.Record.REJECT
9132 Roo.data.Record.COMMIT
9138 * Fires when the data cache has been cleared.
9139 * @param {Store} this
9144 * Fires before a request is made for a new data object. If the beforeload handler returns false
9145 * the load action will be canceled.
9146 * @param {Store} this
9147 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9151 * @event beforeloadadd
9152 * Fires after a new set of Records has been loaded.
9153 * @param {Store} this
9154 * @param {Roo.data.Record[]} records The Records that were loaded
9155 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9157 beforeloadadd : true,
9160 * Fires after a new set of Records has been loaded, before they are added to the store.
9161 * @param {Store} this
9162 * @param {Roo.data.Record[]} records The Records that were loaded
9163 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9164 * @params {Object} return from reader
9168 * @event loadexception
9169 * Fires if an exception occurs in the Proxy during loading.
9170 * Called with the signature of the Proxy's "loadexception" event.
9171 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9174 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9175 * @param {Object} load options
9176 * @param {Object} jsonData from your request (normally this contains the Exception)
9178 loadexception : true
9182 this.proxy = Roo.factory(this.proxy, Roo.data);
9183 this.proxy.xmodule = this.xmodule || false;
9184 this.relayEvents(this.proxy, ["loadexception"]);
9186 this.sortToggle = {};
9187 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9189 Roo.data.Store.superclass.constructor.call(this);
9191 if(this.inlineData){
9192 this.loadData(this.inlineData);
9193 delete this.inlineData;
9197 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9199 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9200 * without a remote query - used by combo/forms at present.
9204 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9207 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9210 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9211 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9214 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9215 * on any HTTP request
9218 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9221 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9225 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9226 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9231 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9232 * loaded or when a record is removed. (defaults to false).
9234 pruneModifiedRecords : false,
9240 * Add Records to the Store and fires the add event.
9241 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9243 add : function(records){
9244 records = [].concat(records);
9245 for(var i = 0, len = records.length; i < len; i++){
9246 records[i].join(this);
9248 var index = this.data.length;
9249 this.data.addAll(records);
9250 this.fireEvent("add", this, records, index);
9254 * Remove a Record from the Store and fires the remove event.
9255 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9257 remove : function(record){
9258 var index = this.data.indexOf(record);
9259 this.data.removeAt(index);
9260 if(this.pruneModifiedRecords){
9261 this.modified.remove(record);
9263 this.fireEvent("remove", this, record, index);
9267 * Remove all Records from the Store and fires the clear event.
9269 removeAll : function(){
9271 if(this.pruneModifiedRecords){
9274 this.fireEvent("clear", this);
9278 * Inserts Records to the Store at the given index and fires the add event.
9279 * @param {Number} index The start index at which to insert the passed Records.
9280 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9282 insert : function(index, records){
9283 records = [].concat(records);
9284 for(var i = 0, len = records.length; i < len; i++){
9285 this.data.insert(index, records[i]);
9286 records[i].join(this);
9288 this.fireEvent("add", this, records, index);
9292 * Get the index within the cache of the passed Record.
9293 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9294 * @return {Number} The index of the passed Record. Returns -1 if not found.
9296 indexOf : function(record){
9297 return this.data.indexOf(record);
9301 * Get the index within the cache of the Record with the passed id.
9302 * @param {String} id The id of the Record to find.
9303 * @return {Number} The index of the Record. Returns -1 if not found.
9305 indexOfId : function(id){
9306 return this.data.indexOfKey(id);
9310 * Get the Record with the specified id.
9311 * @param {String} id The id of the Record to find.
9312 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9314 getById : function(id){
9315 return this.data.key(id);
9319 * Get the Record at the specified index.
9320 * @param {Number} index The index of the Record to find.
9321 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9323 getAt : function(index){
9324 return this.data.itemAt(index);
9328 * Returns a range of Records between specified indices.
9329 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9330 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9331 * @return {Roo.data.Record[]} An array of Records
9333 getRange : function(start, end){
9334 return this.data.getRange(start, end);
9338 storeOptions : function(o){
9339 o = Roo.apply({}, o);
9342 this.lastOptions = o;
9346 * Loads the Record cache from the configured Proxy using the configured Reader.
9348 * If using remote paging, then the first load call must specify the <em>start</em>
9349 * and <em>limit</em> properties in the options.params property to establish the initial
9350 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9352 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9353 * and this call will return before the new data has been loaded. Perform any post-processing
9354 * in a callback function, or in a "load" event handler.</strong>
9356 * @param {Object} options An object containing properties which control loading options:<ul>
9357 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9358 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9359 * passed the following arguments:<ul>
9360 * <li>r : Roo.data.Record[]</li>
9361 * <li>options: Options object from the load call</li>
9362 * <li>success: Boolean success indicator</li></ul></li>
9363 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9364 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9367 load : function(options){
9368 options = options || {};
9369 if(this.fireEvent("beforeload", this, options) !== false){
9370 this.storeOptions(options);
9371 var p = Roo.apply(options.params || {}, this.baseParams);
9372 // if meta was not loaded from remote source.. try requesting it.
9373 if (!this.reader.metaFromRemote) {
9376 if(this.sortInfo && this.remoteSort){
9377 var pn = this.paramNames;
9378 p[pn["sort"]] = this.sortInfo.field;
9379 p[pn["dir"]] = this.sortInfo.direction;
9381 if (this.multiSort) {
9382 var pn = this.paramNames;
9383 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9386 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9391 * Reloads the Record cache from the configured Proxy using the configured Reader and
9392 * the options from the last load operation performed.
9393 * @param {Object} options (optional) An object containing properties which may override the options
9394 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9395 * the most recently used options are reused).
9397 reload : function(options){
9398 this.load(Roo.applyIf(options||{}, this.lastOptions));
9402 // Called as a callback by the Reader during a load operation.
9403 loadRecords : function(o, options, success){
9404 if(!o || success === false){
9405 if(success !== false){
9406 this.fireEvent("load", this, [], options, o);
9408 if(options.callback){
9409 options.callback.call(options.scope || this, [], options, false);
9413 // if data returned failure - throw an exception.
9414 if (o.success === false) {
9415 // show a message if no listener is registered.
9416 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9417 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9419 // loadmask wil be hooked into this..
9420 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9423 var r = o.records, t = o.totalRecords || r.length;
9425 this.fireEvent("beforeloadadd", this, r, options, o);
9427 if(!options || options.add !== true){
9428 if(this.pruneModifiedRecords){
9431 for(var i = 0, len = r.length; i < len; i++){
9435 this.data = this.snapshot;
9436 delete this.snapshot;
9439 this.data.addAll(r);
9440 this.totalLength = t;
9442 this.fireEvent("datachanged", this);
9444 this.totalLength = Math.max(t, this.data.length+r.length);
9447 this.fireEvent("load", this, r, options, o);
9448 if(options.callback){
9449 options.callback.call(options.scope || this, r, options, true);
9455 * Loads data from a passed data block. A Reader which understands the format of the data
9456 * must have been configured in the constructor.
9457 * @param {Object} data The data block from which to read the Records. The format of the data expected
9458 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9459 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9461 loadData : function(o, append){
9462 var r = this.reader.readRecords(o);
9463 this.loadRecords(r, {add: append}, true);
9467 * Gets the number of cached records.
9469 * <em>If using paging, this may not be the total size of the dataset. If the data object
9470 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9471 * the data set size</em>
9473 getCount : function(){
9474 return this.data.length || 0;
9478 * Gets the total number of records in the dataset as returned by the server.
9480 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9481 * the dataset size</em>
9483 getTotalCount : function(){
9484 return this.totalLength || 0;
9488 * Returns the sort state of the Store as an object with two properties:
9490 field {String} The name of the field by which the Records are sorted
9491 direction {String} The sort order, "ASC" or "DESC"
9494 getSortState : function(){
9495 return this.sortInfo;
9499 applySort : function(){
9500 if(this.sortInfo && !this.remoteSort){
9501 var s = this.sortInfo, f = s.field;
9502 var st = this.fields.get(f).sortType;
9503 var fn = function(r1, r2){
9504 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9505 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9507 this.data.sort(s.direction, fn);
9508 if(this.snapshot && this.snapshot != this.data){
9509 this.snapshot.sort(s.direction, fn);
9515 * Sets the default sort column and order to be used by the next load operation.
9516 * @param {String} fieldName The name of the field to sort by.
9517 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9519 setDefaultSort : function(field, dir){
9520 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9525 * If remote sorting is used, the sort is performed on the server, and the cache is
9526 * reloaded. If local sorting is used, the cache is sorted internally.
9527 * @param {String} fieldName The name of the field to sort by.
9528 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9530 sort : function(fieldName, dir){
9531 var f = this.fields.get(fieldName);
9533 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9535 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9536 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9541 this.sortToggle[f.name] = dir;
9542 this.sortInfo = {field: f.name, direction: dir};
9543 if(!this.remoteSort){
9545 this.fireEvent("datachanged", this);
9547 this.load(this.lastOptions);
9552 * Calls the specified function for each of the Records in the cache.
9553 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9554 * Returning <em>false</em> aborts and exits the iteration.
9555 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9557 each : function(fn, scope){
9558 this.data.each(fn, scope);
9562 * Gets all records modified since the last commit. Modified records are persisted across load operations
9563 * (e.g., during paging).
9564 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9566 getModifiedRecords : function(){
9567 return this.modified;
9571 createFilterFn : function(property, value, anyMatch){
9572 if(!value.exec){ // not a regex
9573 value = String(value);
9574 if(value.length == 0){
9577 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9580 return value.test(r.data[property]);
9585 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9586 * @param {String} property A field on your records
9587 * @param {Number} start The record index to start at (defaults to 0)
9588 * @param {Number} end The last record index to include (defaults to length - 1)
9589 * @return {Number} The sum
9591 sum : function(property, start, end){
9592 var rs = this.data.items, v = 0;
9594 end = (end || end === 0) ? end : rs.length-1;
9596 for(var i = start; i <= end; i++){
9597 v += (rs[i].data[property] || 0);
9603 * Filter the records by a specified property.
9604 * @param {String} field A field on your records
9605 * @param {String/RegExp} value Either a string that the field
9606 * should start with or a RegExp to test against the field
9607 * @param {Boolean} anyMatch True to match any part not just the beginning
9609 filter : function(property, value, anyMatch){
9610 var fn = this.createFilterFn(property, value, anyMatch);
9611 return fn ? this.filterBy(fn) : this.clearFilter();
9615 * Filter by a function. The specified function will be called with each
9616 * record in this data source. If the function returns true the record is included,
9617 * otherwise it is filtered.
9618 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9619 * @param {Object} scope (optional) The scope of the function (defaults to this)
9621 filterBy : function(fn, scope){
9622 this.snapshot = this.snapshot || this.data;
9623 this.data = this.queryBy(fn, scope||this);
9624 this.fireEvent("datachanged", this);
9628 * Query the records by a specified property.
9629 * @param {String} field A field on your records
9630 * @param {String/RegExp} value Either a string that the field
9631 * should start with or a RegExp to test against the field
9632 * @param {Boolean} anyMatch True to match any part not just the beginning
9633 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9635 query : function(property, value, anyMatch){
9636 var fn = this.createFilterFn(property, value, anyMatch);
9637 return fn ? this.queryBy(fn) : this.data.clone();
9641 * Query by a function. The specified function will be called with each
9642 * record in this data source. If the function returns true the record is included
9644 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9645 * @param {Object} scope (optional) The scope of the function (defaults to this)
9646 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9648 queryBy : function(fn, scope){
9649 var data = this.snapshot || this.data;
9650 return data.filterBy(fn, scope||this);
9654 * Collects unique values for a particular dataIndex from this store.
9655 * @param {String} dataIndex The property to collect
9656 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9657 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9658 * @return {Array} An array of the unique values
9660 collect : function(dataIndex, allowNull, bypassFilter){
9661 var d = (bypassFilter === true && this.snapshot) ?
9662 this.snapshot.items : this.data.items;
9663 var v, sv, r = [], l = {};
9664 for(var i = 0, len = d.length; i < len; i++){
9665 v = d[i].data[dataIndex];
9667 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9676 * Revert to a view of the Record cache with no filtering applied.
9677 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9679 clearFilter : function(suppressEvent){
9680 if(this.snapshot && this.snapshot != this.data){
9681 this.data = this.snapshot;
9682 delete this.snapshot;
9683 if(suppressEvent !== true){
9684 this.fireEvent("datachanged", this);
9690 afterEdit : function(record){
9691 if(this.modified.indexOf(record) == -1){
9692 this.modified.push(record);
9694 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9698 afterReject : function(record){
9699 this.modified.remove(record);
9700 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9704 afterCommit : function(record){
9705 this.modified.remove(record);
9706 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9710 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9711 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9713 commitChanges : function(){
9714 var m = this.modified.slice(0);
9716 for(var i = 0, len = m.length; i < len; i++){
9722 * Cancel outstanding changes on all changed records.
9724 rejectChanges : function(){
9725 var m = this.modified.slice(0);
9727 for(var i = 0, len = m.length; i < len; i++){
9732 onMetaChange : function(meta, rtype, o){
9733 this.recordType = rtype;
9734 this.fields = rtype.prototype.fields;
9735 delete this.snapshot;
9736 this.sortInfo = meta.sortInfo || this.sortInfo;
9738 this.fireEvent('metachange', this, this.reader.meta);
9741 moveIndex : function(data, type)
9743 var index = this.indexOf(data);
9745 var newIndex = index + type;
9749 this.insert(newIndex, data);
9754 * Ext JS Library 1.1.1
9755 * Copyright(c) 2006-2007, Ext JS, LLC.
9757 * Originally Released Under LGPL - original licence link has changed is not relivant.
9760 * <script type="text/javascript">
9764 * @class Roo.data.SimpleStore
9765 * @extends Roo.data.Store
9766 * Small helper class to make creating Stores from Array data easier.
9767 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9768 * @cfg {Array} fields An array of field definition objects, or field name strings.
9769 * @cfg {Array} data The multi-dimensional array of data
9771 * @param {Object} config
9773 Roo.data.SimpleStore = function(config){
9774 Roo.data.SimpleStore.superclass.constructor.call(this, {
9776 reader: new Roo.data.ArrayReader({
9779 Roo.data.Record.create(config.fields)
9781 proxy : new Roo.data.MemoryProxy(config.data)
9785 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9787 * Ext JS Library 1.1.1
9788 * Copyright(c) 2006-2007, Ext JS, LLC.
9790 * Originally Released Under LGPL - original licence link has changed is not relivant.
9793 * <script type="text/javascript">
9798 * @extends Roo.data.Store
9799 * @class Roo.data.JsonStore
9800 * Small helper class to make creating Stores for JSON data easier. <br/>
9802 var store = new Roo.data.JsonStore({
9803 url: 'get-images.php',
9805 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9808 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9809 * JsonReader and HttpProxy (unless inline data is provided).</b>
9810 * @cfg {Array} fields An array of field definition objects, or field name strings.
9812 * @param {Object} config
9814 Roo.data.JsonStore = function(c){
9815 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9816 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9817 reader: new Roo.data.JsonReader(c, c.fields)
9820 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9822 * Ext JS Library 1.1.1
9823 * Copyright(c) 2006-2007, Ext JS, LLC.
9825 * Originally Released Under LGPL - original licence link has changed is not relivant.
9828 * <script type="text/javascript">
9832 Roo.data.Field = function(config){
9833 if(typeof config == "string"){
9834 config = {name: config};
9836 Roo.apply(this, config);
9842 var st = Roo.data.SortTypes;
9843 // named sortTypes are supported, here we look them up
9844 if(typeof this.sortType == "string"){
9845 this.sortType = st[this.sortType];
9848 // set default sortType for strings and dates
9852 this.sortType = st.asUCString;
9855 this.sortType = st.asDate;
9858 this.sortType = st.none;
9863 var stripRe = /[\$,%]/g;
9865 // prebuilt conversion function for this field, instead of
9866 // switching every time we're reading a value
9868 var cv, dateFormat = this.dateFormat;
9873 cv = function(v){ return v; };
9876 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9880 return v !== undefined && v !== null && v !== '' ?
9881 parseInt(String(v).replace(stripRe, ""), 10) : '';
9886 return v !== undefined && v !== null && v !== '' ?
9887 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9892 cv = function(v){ return v === true || v === "true" || v == 1; };
9899 if(v instanceof Date){
9903 if(dateFormat == "timestamp"){
9904 return new Date(v*1000);
9906 return Date.parseDate(v, dateFormat);
9908 var parsed = Date.parse(v);
9909 return parsed ? new Date(parsed) : null;
9918 Roo.data.Field.prototype = {
9926 * Ext JS Library 1.1.1
9927 * Copyright(c) 2006-2007, Ext JS, LLC.
9929 * Originally Released Under LGPL - original licence link has changed is not relivant.
9932 * <script type="text/javascript">
9935 // Base class for reading structured data from a data source. This class is intended to be
9936 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9939 * @class Roo.data.DataReader
9940 * Base class for reading structured data from a data source. This class is intended to be
9941 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9944 Roo.data.DataReader = function(meta, recordType){
9948 this.recordType = recordType instanceof Array ?
9949 Roo.data.Record.create(recordType) : recordType;
9952 Roo.data.DataReader.prototype = {
9954 * Create an empty record
9955 * @param {Object} data (optional) - overlay some values
9956 * @return {Roo.data.Record} record created.
9958 newRow : function(d) {
9960 this.recordType.prototype.fields.each(function(c) {
9962 case 'int' : da[c.name] = 0; break;
9963 case 'date' : da[c.name] = new Date(); break;
9964 case 'float' : da[c.name] = 0.0; break;
9965 case 'boolean' : da[c.name] = false; break;
9966 default : da[c.name] = ""; break;
9970 return new this.recordType(Roo.apply(da, d));
9975 * Ext JS Library 1.1.1
9976 * Copyright(c) 2006-2007, Ext JS, LLC.
9978 * Originally Released Under LGPL - original licence link has changed is not relivant.
9981 * <script type="text/javascript">
9985 * @class Roo.data.DataProxy
9986 * @extends Roo.data.Observable
9987 * This class is an abstract base class for implementations which provide retrieval of
9988 * unformatted data objects.<br>
9990 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9991 * (of the appropriate type which knows how to parse the data object) to provide a block of
9992 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9994 * Custom implementations must implement the load method as described in
9995 * {@link Roo.data.HttpProxy#load}.
9997 Roo.data.DataProxy = function(){
10000 * @event beforeload
10001 * Fires before a network request is made to retrieve a data object.
10002 * @param {Object} This DataProxy object.
10003 * @param {Object} params The params parameter to the load function.
10008 * Fires before the load method's callback is called.
10009 * @param {Object} This DataProxy object.
10010 * @param {Object} o The data object.
10011 * @param {Object} arg The callback argument object passed to the load function.
10015 * @event loadexception
10016 * Fires if an Exception occurs during data retrieval.
10017 * @param {Object} This DataProxy object.
10018 * @param {Object} o The data object.
10019 * @param {Object} arg The callback argument object passed to the load function.
10020 * @param {Object} e The Exception.
10022 loadexception : true
10024 Roo.data.DataProxy.superclass.constructor.call(this);
10027 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10030 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10034 * Ext JS Library 1.1.1
10035 * Copyright(c) 2006-2007, Ext JS, LLC.
10037 * Originally Released Under LGPL - original licence link has changed is not relivant.
10040 * <script type="text/javascript">
10043 * @class Roo.data.MemoryProxy
10044 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10045 * to the Reader when its load method is called.
10047 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10049 Roo.data.MemoryProxy = function(data){
10053 Roo.data.MemoryProxy.superclass.constructor.call(this);
10057 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10059 * Load data from the requested source (in this case an in-memory
10060 * data object passed to the constructor), read the data object into
10061 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10062 * process that block using the passed callback.
10063 * @param {Object} params This parameter is not used by the MemoryProxy class.
10064 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10065 * object into a block of Roo.data.Records.
10066 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10067 * The function must be passed <ul>
10068 * <li>The Record block object</li>
10069 * <li>The "arg" argument from the load function</li>
10070 * <li>A boolean success indicator</li>
10072 * @param {Object} scope The scope in which to call the callback
10073 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10075 load : function(params, reader, callback, scope, arg){
10076 params = params || {};
10079 result = reader.readRecords(this.data);
10081 this.fireEvent("loadexception", this, arg, null, e);
10082 callback.call(scope, null, arg, false);
10085 callback.call(scope, result, arg, true);
10089 update : function(params, records){
10094 * Ext JS Library 1.1.1
10095 * Copyright(c) 2006-2007, Ext JS, LLC.
10097 * Originally Released Under LGPL - original licence link has changed is not relivant.
10100 * <script type="text/javascript">
10103 * @class Roo.data.HttpProxy
10104 * @extends Roo.data.DataProxy
10105 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10106 * configured to reference a certain URL.<br><br>
10108 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10109 * from which the running page was served.<br><br>
10111 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10113 * Be aware that to enable the browser to parse an XML document, the server must set
10114 * the Content-Type header in the HTTP response to "text/xml".
10116 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10117 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10118 * will be used to make the request.
10120 Roo.data.HttpProxy = function(conn){
10121 Roo.data.HttpProxy.superclass.constructor.call(this);
10122 // is conn a conn config or a real conn?
10124 this.useAjax = !conn || !conn.events;
10128 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10129 // thse are take from connection...
10132 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10135 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10136 * extra parameters to each request made by this object. (defaults to undefined)
10139 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10140 * to each request made by this object. (defaults to undefined)
10143 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
10146 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10149 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10155 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10159 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10160 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10161 * a finer-grained basis than the DataProxy events.
10163 getConnection : function(){
10164 return this.useAjax ? Roo.Ajax : this.conn;
10168 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10169 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10170 * process that block using the passed callback.
10171 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10172 * for the request to the remote server.
10173 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10174 * object into a block of Roo.data.Records.
10175 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10176 * The function must be passed <ul>
10177 * <li>The Record block object</li>
10178 * <li>The "arg" argument from the load function</li>
10179 * <li>A boolean success indicator</li>
10181 * @param {Object} scope The scope in which to call the callback
10182 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10184 load : function(params, reader, callback, scope, arg){
10185 if(this.fireEvent("beforeload", this, params) !== false){
10187 params : params || {},
10189 callback : callback,
10194 callback : this.loadResponse,
10198 Roo.applyIf(o, this.conn);
10199 if(this.activeRequest){
10200 Roo.Ajax.abort(this.activeRequest);
10202 this.activeRequest = Roo.Ajax.request(o);
10204 this.conn.request(o);
10207 callback.call(scope||this, null, arg, false);
10212 loadResponse : function(o, success, response){
10213 delete this.activeRequest;
10215 this.fireEvent("loadexception", this, o, response);
10216 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10221 result = o.reader.read(response);
10223 this.fireEvent("loadexception", this, o, response, e);
10224 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10228 this.fireEvent("load", this, o, o.request.arg);
10229 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10233 update : function(dataSet){
10238 updateResponse : function(dataSet){
10243 * Ext JS Library 1.1.1
10244 * Copyright(c) 2006-2007, Ext JS, LLC.
10246 * Originally Released Under LGPL - original licence link has changed is not relivant.
10249 * <script type="text/javascript">
10253 * @class Roo.data.ScriptTagProxy
10254 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10255 * other than the originating domain of the running page.<br><br>
10257 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
10258 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10260 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10261 * source code that is used as the source inside a <script> tag.<br><br>
10263 * In order for the browser to process the returned data, the server must wrap the data object
10264 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10265 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10266 * depending on whether the callback name was passed:
10269 boolean scriptTag = false;
10270 String cb = request.getParameter("callback");
10273 response.setContentType("text/javascript");
10275 response.setContentType("application/x-json");
10277 Writer out = response.getWriter();
10279 out.write(cb + "(");
10281 out.print(dataBlock.toJsonString());
10288 * @param {Object} config A configuration object.
10290 Roo.data.ScriptTagProxy = function(config){
10291 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10292 Roo.apply(this, config);
10293 this.head = document.getElementsByTagName("head")[0];
10296 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10298 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10300 * @cfg {String} url The URL from which to request the data object.
10303 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10307 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10308 * the server the name of the callback function set up by the load call to process the returned data object.
10309 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10310 * javascript output which calls this named function passing the data object as its only parameter.
10312 callbackParam : "callback",
10314 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10315 * name to the request.
10320 * Load data from the configured URL, read the data object into
10321 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10322 * process that block using the passed callback.
10323 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10324 * for the request to the remote server.
10325 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10326 * object into a block of Roo.data.Records.
10327 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10328 * The function must be passed <ul>
10329 * <li>The Record block object</li>
10330 * <li>The "arg" argument from the load function</li>
10331 * <li>A boolean success indicator</li>
10333 * @param {Object} scope The scope in which to call the callback
10334 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10336 load : function(params, reader, callback, scope, arg){
10337 if(this.fireEvent("beforeload", this, params) !== false){
10339 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10341 var url = this.url;
10342 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10344 url += "&_dc=" + (new Date().getTime());
10346 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10349 cb : "stcCallback"+transId,
10350 scriptId : "stcScript"+transId,
10354 callback : callback,
10360 window[trans.cb] = function(o){
10361 conn.handleResponse(o, trans);
10364 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10366 if(this.autoAbort !== false){
10370 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10372 var script = document.createElement("script");
10373 script.setAttribute("src", url);
10374 script.setAttribute("type", "text/javascript");
10375 script.setAttribute("id", trans.scriptId);
10376 this.head.appendChild(script);
10378 this.trans = trans;
10380 callback.call(scope||this, null, arg, false);
10385 isLoading : function(){
10386 return this.trans ? true : false;
10390 * Abort the current server request.
10392 abort : function(){
10393 if(this.isLoading()){
10394 this.destroyTrans(this.trans);
10399 destroyTrans : function(trans, isLoaded){
10400 this.head.removeChild(document.getElementById(trans.scriptId));
10401 clearTimeout(trans.timeoutId);
10403 window[trans.cb] = undefined;
10405 delete window[trans.cb];
10408 // if hasn't been loaded, wait for load to remove it to prevent script error
10409 window[trans.cb] = function(){
10410 window[trans.cb] = undefined;
10412 delete window[trans.cb];
10419 handleResponse : function(o, trans){
10420 this.trans = false;
10421 this.destroyTrans(trans, true);
10424 result = trans.reader.readRecords(o);
10426 this.fireEvent("loadexception", this, o, trans.arg, e);
10427 trans.callback.call(trans.scope||window, null, trans.arg, false);
10430 this.fireEvent("load", this, o, trans.arg);
10431 trans.callback.call(trans.scope||window, result, trans.arg, true);
10435 handleFailure : function(trans){
10436 this.trans = false;
10437 this.destroyTrans(trans, false);
10438 this.fireEvent("loadexception", this, null, trans.arg);
10439 trans.callback.call(trans.scope||window, null, trans.arg, false);
10443 * Ext JS Library 1.1.1
10444 * Copyright(c) 2006-2007, Ext JS, LLC.
10446 * Originally Released Under LGPL - original licence link has changed is not relivant.
10449 * <script type="text/javascript">
10453 * @class Roo.data.JsonReader
10454 * @extends Roo.data.DataReader
10455 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10456 * based on mappings in a provided Roo.data.Record constructor.
10458 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10459 * in the reply previously.
10464 var RecordDef = Roo.data.Record.create([
10465 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10466 {name: 'occupation'} // This field will use "occupation" as the mapping.
10468 var myReader = new Roo.data.JsonReader({
10469 totalProperty: "results", // The property which contains the total dataset size (optional)
10470 root: "rows", // The property which contains an Array of row objects
10471 id: "id" // The property within each row object that provides an ID for the record (optional)
10475 * This would consume a JSON file like this:
10477 { 'results': 2, 'rows': [
10478 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10479 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10482 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10483 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10484 * paged from the remote server.
10485 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10486 * @cfg {String} root name of the property which contains the Array of row objects.
10487 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10489 * Create a new JsonReader
10490 * @param {Object} meta Metadata configuration options
10491 * @param {Object} recordType Either an Array of field definition objects,
10492 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10494 Roo.data.JsonReader = function(meta, recordType){
10497 // set some defaults:
10498 Roo.applyIf(meta, {
10499 totalProperty: 'total',
10500 successProperty : 'success',
10505 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10507 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10510 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10511 * Used by Store query builder to append _requestMeta to params.
10514 metaFromRemote : false,
10516 * This method is only used by a DataProxy which has retrieved data from a remote server.
10517 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10518 * @return {Object} data A data block which is used by an Roo.data.Store object as
10519 * a cache of Roo.data.Records.
10521 read : function(response){
10522 var json = response.responseText;
10524 var o = /* eval:var:o */ eval("("+json+")");
10526 throw {message: "JsonReader.read: Json object not found"};
10532 this.metaFromRemote = true;
10533 this.meta = o.metaData;
10534 this.recordType = Roo.data.Record.create(o.metaData.fields);
10535 this.onMetaChange(this.meta, this.recordType, o);
10537 return this.readRecords(o);
10540 // private function a store will implement
10541 onMetaChange : function(meta, recordType, o){
10548 simpleAccess: function(obj, subsc) {
10555 getJsonAccessor: function(){
10557 return function(expr) {
10559 return(re.test(expr))
10560 ? new Function("obj", "return obj." + expr)
10565 return Roo.emptyFn;
10570 * Create a data block containing Roo.data.Records from an XML document.
10571 * @param {Object} o An object which contains an Array of row objects in the property specified
10572 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10573 * which contains the total size of the dataset.
10574 * @return {Object} data A data block which is used by an Roo.data.Store object as
10575 * a cache of Roo.data.Records.
10577 readRecords : function(o){
10579 * After any data loads, the raw JSON data is available for further custom processing.
10583 var s = this.meta, Record = this.recordType,
10584 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10586 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10588 if(s.totalProperty) {
10589 this.getTotal = this.getJsonAccessor(s.totalProperty);
10591 if(s.successProperty) {
10592 this.getSuccess = this.getJsonAccessor(s.successProperty);
10594 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10596 var g = this.getJsonAccessor(s.id);
10597 this.getId = function(rec) {
10599 return (r === undefined || r === "") ? null : r;
10602 this.getId = function(){return null;};
10605 for(var jj = 0; jj < fl; jj++){
10607 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10608 this.ef[jj] = this.getJsonAccessor(map);
10612 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10613 if(s.totalProperty){
10614 var vt = parseInt(this.getTotal(o), 10);
10619 if(s.successProperty){
10620 var vs = this.getSuccess(o);
10621 if(vs === false || vs === 'false'){
10626 for(var i = 0; i < c; i++){
10629 var id = this.getId(n);
10630 for(var j = 0; j < fl; j++){
10632 var v = this.ef[j](n);
10634 Roo.log('missing convert for ' + f.name);
10638 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10640 var record = new Record(values, id);
10642 records[i] = record;
10648 totalRecords : totalRecords
10653 * Ext JS Library 1.1.1
10654 * Copyright(c) 2006-2007, Ext JS, LLC.
10656 * Originally Released Under LGPL - original licence link has changed is not relivant.
10659 * <script type="text/javascript">
10663 * @class Roo.data.ArrayReader
10664 * @extends Roo.data.DataReader
10665 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10666 * Each element of that Array represents a row of data fields. The
10667 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10668 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10672 var RecordDef = Roo.data.Record.create([
10673 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10674 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10676 var myReader = new Roo.data.ArrayReader({
10677 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10681 * This would consume an Array like this:
10683 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10685 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10687 * Create a new JsonReader
10688 * @param {Object} meta Metadata configuration options.
10689 * @param {Object} recordType Either an Array of field definition objects
10690 * as specified to {@link Roo.data.Record#create},
10691 * or an {@link Roo.data.Record} object
10692 * created using {@link Roo.data.Record#create}.
10694 Roo.data.ArrayReader = function(meta, recordType){
10695 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10698 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10700 * Create a data block containing Roo.data.Records from an XML document.
10701 * @param {Object} o An Array of row objects which represents the dataset.
10702 * @return {Object} data A data block which is used by an Roo.data.Store object as
10703 * a cache of Roo.data.Records.
10705 readRecords : function(o){
10706 var sid = this.meta ? this.meta.id : null;
10707 var recordType = this.recordType, fields = recordType.prototype.fields;
10710 for(var i = 0; i < root.length; i++){
10713 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10714 for(var j = 0, jlen = fields.length; j < jlen; j++){
10715 var f = fields.items[j];
10716 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10717 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10719 values[f.name] = v;
10721 var record = new recordType(values, id);
10723 records[records.length] = record;
10727 totalRecords : records.length
10736 * @class Roo.bootstrap.ComboBox
10737 * @extends Roo.bootstrap.TriggerField
10738 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10739 * @cfg {Boolean} append (true|false) default false
10740 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10741 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10742 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10743 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10744 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10746 * Create a new ComboBox.
10747 * @param {Object} config Configuration options
10749 Roo.bootstrap.ComboBox = function(config){
10750 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10754 * Fires when the dropdown list is expanded
10755 * @param {Roo.bootstrap.ComboBox} combo This combo box
10760 * Fires when the dropdown list is collapsed
10761 * @param {Roo.bootstrap.ComboBox} combo This combo box
10765 * @event beforeselect
10766 * Fires before a list item is selected. Return false to cancel the selection.
10767 * @param {Roo.bootstrap.ComboBox} combo This combo box
10768 * @param {Roo.data.Record} record The data record returned from the underlying store
10769 * @param {Number} index The index of the selected item in the dropdown list
10771 'beforeselect' : true,
10774 * Fires when a list item is selected
10775 * @param {Roo.bootstrap.ComboBox} combo This combo box
10776 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10777 * @param {Number} index The index of the selected item in the dropdown list
10781 * @event beforequery
10782 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10783 * The event object passed has these properties:
10784 * @param {Roo.bootstrap.ComboBox} combo This combo box
10785 * @param {String} query The query
10786 * @param {Boolean} forceAll true to force "all" query
10787 * @param {Boolean} cancel true to cancel the query
10788 * @param {Object} e The query event object
10790 'beforequery': true,
10793 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10794 * @param {Roo.bootstrap.ComboBox} combo This combo box
10799 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10800 * @param {Roo.bootstrap.ComboBox} combo This combo box
10801 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10806 * Fires when the remove value from the combobox array
10807 * @param {Roo.bootstrap.ComboBox} combo This combo box
10811 * @event specialfilter
10812 * Fires when specialfilter
10813 * @param {Roo.bootstrap.ComboBox} combo This combo box
10815 'specialfilter' : true
10820 this.tickItems = [];
10822 this.selectedIndex = -1;
10823 if(this.mode == 'local'){
10824 if(config.queryDelay === undefined){
10825 this.queryDelay = 10;
10827 if(config.minChars === undefined){
10833 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10836 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10837 * rendering into an Roo.Editor, defaults to false)
10840 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10841 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10844 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10847 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10848 * the dropdown list (defaults to undefined, with no header element)
10852 * @cfg {String/Roo.Template} tpl The template to use to render the output
10856 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10858 listWidth: undefined,
10860 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10861 * mode = 'remote' or 'text' if mode = 'local')
10863 displayField: undefined,
10866 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10867 * mode = 'remote' or 'value' if mode = 'local').
10868 * Note: use of a valueField requires the user make a selection
10869 * in order for a value to be mapped.
10871 valueField: undefined,
10875 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10876 * field's data value (defaults to the underlying DOM element's name)
10878 hiddenName: undefined,
10880 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10884 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10886 selectedClass: 'active',
10889 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10893 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10894 * anchor positions (defaults to 'tl-bl')
10896 listAlign: 'tl-bl?',
10898 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10902 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10903 * query specified by the allQuery config option (defaults to 'query')
10905 triggerAction: 'query',
10907 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10908 * (defaults to 4, does not apply if editable = false)
10912 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10913 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10917 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10918 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10922 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10923 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10927 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10928 * when editable = true (defaults to false)
10930 selectOnFocus:false,
10932 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10934 queryParam: 'query',
10936 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10937 * when mode = 'remote' (defaults to 'Loading...')
10939 loadingText: 'Loading...',
10941 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10945 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10949 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10950 * traditional select (defaults to true)
10954 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10958 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10962 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10963 * listWidth has a higher value)
10967 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10968 * allow the user to set arbitrary text into the field (defaults to false)
10970 forceSelection:false,
10972 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10973 * if typeAhead = true (defaults to 250)
10975 typeAheadDelay : 250,
10977 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10978 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10980 valueNotFoundText : undefined,
10982 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10984 blockFocus : false,
10987 * @cfg {Boolean} disableClear Disable showing of clear button.
10989 disableClear : false,
10991 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10993 alwaysQuery : false,
10996 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11001 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11003 invalidClass : "has-warning",
11006 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11008 validClass : "has-success",
11011 * @cfg {Boolean} specialFilter (true|false) special filter default false
11013 specialFilter : false,
11025 btnPosition : 'right',
11026 triggerList : true,
11027 showToggleBtn : true,
11028 // element that contains real text value.. (when hidden is used..)
11030 getAutoCreate : function()
11037 if(!this.tickable){
11038 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11043 * ComboBox with tickable selections
11046 var align = this.labelAlign || this.parentLabelAlign();
11049 cls : 'form-group roo-combobox-tickable' //input-group
11054 cls : 'tickable-buttons',
11059 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11066 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11073 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11080 buttons.cn.unshift({
11082 cls: 'select2-search-field-input'
11088 Roo.each(buttons.cn, function(c){
11090 c.cls += ' btn-' + _this.size;
11093 if (_this.disabled) {
11104 cls: 'form-hidden-field'
11108 cls: 'select2-choices',
11112 cls: 'select2-search-field',
11124 cls: 'select2-container input-group select2-container-multi',
11129 // cls: 'typeahead typeahead-long dropdown-menu',
11130 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11135 if(this.hasFeedback && !this.allowBlank){
11139 cls: 'glyphicon form-control-feedback'
11142 combobox.cn.push(feedback);
11145 if (align ==='left' && this.fieldLabel.length) {
11147 Roo.log("left and has label");
11153 cls : 'control-label col-sm-' + this.labelWidth,
11154 html : this.fieldLabel
11158 cls : "col-sm-" + (12 - this.labelWidth),
11165 } else if ( this.fieldLabel.length) {
11171 //cls : 'input-group-addon',
11172 html : this.fieldLabel
11182 Roo.log(" no label && no align");
11189 ['xs','sm','md','lg'].map(function(size){
11190 if (settings[size]) {
11191 cfg.cls += ' col-' + size + '-' + settings[size];
11200 initEvents: function()
11204 throw "can not find store for combo";
11206 this.store = Roo.factory(this.store, Roo.data);
11209 this.initTickableEvents();
11213 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11215 if(this.hiddenName){
11217 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11219 this.hiddenField.dom.value =
11220 this.hiddenValue !== undefined ? this.hiddenValue :
11221 this.value !== undefined ? this.value : '';
11223 // prevent input submission
11224 this.el.dom.removeAttribute('name');
11225 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11230 // this.el.dom.setAttribute('autocomplete', 'off');
11233 var cls = 'x-combo-list';
11235 //this.list = new Roo.Layer({
11236 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11242 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11243 _this.list.setWidth(lw);
11246 this.list.on('mouseover', this.onViewOver, this);
11247 this.list.on('mousemove', this.onViewMove, this);
11249 this.list.on('scroll', this.onViewScroll, this);
11252 this.list.swallowEvent('mousewheel');
11253 this.assetHeight = 0;
11256 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11257 this.assetHeight += this.header.getHeight();
11260 this.innerList = this.list.createChild({cls:cls+'-inner'});
11261 this.innerList.on('mouseover', this.onViewOver, this);
11262 this.innerList.on('mousemove', this.onViewMove, this);
11263 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11265 if(this.allowBlank && !this.pageSize && !this.disableClear){
11266 this.footer = this.list.createChild({cls:cls+'-ft'});
11267 this.pageTb = new Roo.Toolbar(this.footer);
11271 this.footer = this.list.createChild({cls:cls+'-ft'});
11272 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11273 {pageSize: this.pageSize});
11277 if (this.pageTb && this.allowBlank && !this.disableClear) {
11279 this.pageTb.add(new Roo.Toolbar.Fill(), {
11280 cls: 'x-btn-icon x-btn-clear',
11282 handler: function()
11285 _this.clearValue();
11286 _this.onSelect(false, -1);
11291 this.assetHeight += this.footer.getHeight();
11296 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11299 this.view = new Roo.View(this.list, this.tpl, {
11300 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11302 //this.view.wrapEl.setDisplayed(false);
11303 this.view.on('click', this.onViewClick, this);
11307 this.store.on('beforeload', this.onBeforeLoad, this);
11308 this.store.on('load', this.onLoad, this);
11309 this.store.on('loadexception', this.onLoadException, this);
11311 if(this.resizable){
11312 this.resizer = new Roo.Resizable(this.list, {
11313 pinned:true, handles:'se'
11315 this.resizer.on('resize', function(r, w, h){
11316 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11317 this.listWidth = w;
11318 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11319 this.restrictHeight();
11321 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11324 if(!this.editable){
11325 this.editable = true;
11326 this.setEditable(false);
11331 if (typeof(this.events.add.listeners) != 'undefined') {
11333 this.addicon = this.wrap.createChild(
11334 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11336 this.addicon.on('click', function(e) {
11337 this.fireEvent('add', this);
11340 if (typeof(this.events.edit.listeners) != 'undefined') {
11342 this.editicon = this.wrap.createChild(
11343 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11344 if (this.addicon) {
11345 this.editicon.setStyle('margin-left', '40px');
11347 this.editicon.on('click', function(e) {
11349 // we fire even if inothing is selected..
11350 this.fireEvent('edit', this, this.lastData );
11356 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11357 "up" : function(e){
11358 this.inKeyMode = true;
11362 "down" : function(e){
11363 if(!this.isExpanded()){
11364 this.onTriggerClick();
11366 this.inKeyMode = true;
11371 "enter" : function(e){
11372 // this.onViewClick();
11376 if(this.fireEvent("specialkey", this, e)){
11377 this.onViewClick(false);
11383 "esc" : function(e){
11387 "tab" : function(e){
11390 if(this.fireEvent("specialkey", this, e)){
11391 this.onViewClick(false);
11399 doRelay : function(foo, bar, hname){
11400 if(hname == 'down' || this.scope.isExpanded()){
11401 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11410 this.queryDelay = Math.max(this.queryDelay || 10,
11411 this.mode == 'local' ? 10 : 250);
11414 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11416 if(this.typeAhead){
11417 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11419 if(this.editable !== false){
11420 this.inputEl().on("keyup", this.onKeyUp, this);
11422 if(this.forceSelection){
11423 this.inputEl().on('blur', this.doForce, this);
11427 this.choices = this.el.select('ul.select2-choices', true).first();
11428 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11432 initTickableEvents: function()
11436 if(this.hiddenName){
11438 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11440 this.hiddenField.dom.value =
11441 this.hiddenValue !== undefined ? this.hiddenValue :
11442 this.value !== undefined ? this.value : '';
11444 // prevent input submission
11445 this.el.dom.removeAttribute('name');
11446 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11451 // this.list = this.el.select('ul.dropdown-menu',true).first();
11453 this.choices = this.el.select('ul.select2-choices', true).first();
11454 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11455 if(this.triggerList){
11456 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11459 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11460 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11462 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11463 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11465 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11466 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11468 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11469 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11470 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11473 this.cancelBtn.hide();
11478 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11479 _this.list.setWidth(lw);
11482 this.list.on('mouseover', this.onViewOver, this);
11483 this.list.on('mousemove', this.onViewMove, this);
11485 this.list.on('scroll', this.onViewScroll, this);
11488 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11491 this.view = new Roo.View(this.list, this.tpl, {
11492 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11495 //this.view.wrapEl.setDisplayed(false);
11496 this.view.on('click', this.onViewClick, this);
11500 this.store.on('beforeload', this.onBeforeLoad, this);
11501 this.store.on('load', this.onLoad, this);
11502 this.store.on('loadexception', this.onLoadException, this);
11505 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11506 "up" : function(e){
11507 this.inKeyMode = true;
11511 "down" : function(e){
11512 this.inKeyMode = true;
11516 "enter" : function(e){
11517 if(this.fireEvent("specialkey", this, e)){
11518 this.onViewClick(false);
11524 "esc" : function(e){
11525 this.onTickableFooterButtonClick(e, false, false);
11528 "tab" : function(e){
11529 this.fireEvent("specialkey", this, e);
11531 this.onTickableFooterButtonClick(e, false, false);
11538 doRelay : function(e, fn, key){
11539 if(this.scope.isExpanded()){
11540 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11549 this.queryDelay = Math.max(this.queryDelay || 10,
11550 this.mode == 'local' ? 10 : 250);
11553 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11555 if(this.typeAhead){
11556 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11559 if(this.editable !== false){
11560 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11565 onDestroy : function(){
11567 this.view.setStore(null);
11568 this.view.el.removeAllListeners();
11569 this.view.el.remove();
11570 this.view.purgeListeners();
11573 this.list.dom.innerHTML = '';
11577 this.store.un('beforeload', this.onBeforeLoad, this);
11578 this.store.un('load', this.onLoad, this);
11579 this.store.un('loadexception', this.onLoadException, this);
11581 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11585 fireKey : function(e){
11586 if(e.isNavKeyPress() && !this.list.isVisible()){
11587 this.fireEvent("specialkey", this, e);
11592 onResize: function(w, h){
11593 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11595 // if(typeof w != 'number'){
11596 // // we do not handle it!?!?
11599 // var tw = this.trigger.getWidth();
11600 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11601 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11603 // this.inputEl().setWidth( this.adjustWidth('input', x));
11605 // //this.trigger.setStyle('left', x+'px');
11607 // if(this.list && this.listWidth === undefined){
11608 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11609 // this.list.setWidth(lw);
11610 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11618 * Allow or prevent the user from directly editing the field text. If false is passed,
11619 * the user will only be able to select from the items defined in the dropdown list. This method
11620 * is the runtime equivalent of setting the 'editable' config option at config time.
11621 * @param {Boolean} value True to allow the user to directly edit the field text
11623 setEditable : function(value){
11624 if(value == this.editable){
11627 this.editable = value;
11629 this.inputEl().dom.setAttribute('readOnly', true);
11630 this.inputEl().on('mousedown', this.onTriggerClick, this);
11631 this.inputEl().addClass('x-combo-noedit');
11633 this.inputEl().dom.setAttribute('readOnly', false);
11634 this.inputEl().un('mousedown', this.onTriggerClick, this);
11635 this.inputEl().removeClass('x-combo-noedit');
11641 onBeforeLoad : function(combo,opts){
11642 if(!this.hasFocus){
11646 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11648 this.restrictHeight();
11649 this.selectedIndex = -1;
11653 onLoad : function(){
11655 this.hasQuery = false;
11657 if(!this.hasFocus){
11661 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11662 this.loading.hide();
11665 if(this.store.getCount() > 0){
11667 this.restrictHeight();
11668 if(this.lastQuery == this.allQuery){
11669 if(this.editable && !this.tickable){
11670 this.inputEl().dom.select();
11674 !this.selectByValue(this.value, true) &&
11677 !this.store.lastOptions ||
11678 typeof(this.store.lastOptions.add) == 'undefined' ||
11679 this.store.lastOptions.add != true
11682 this.select(0, true);
11685 if(this.autoFocus){
11688 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11689 this.taTask.delay(this.typeAheadDelay);
11693 this.onEmptyResults();
11699 onLoadException : function()
11701 this.hasQuery = false;
11703 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11704 this.loading.hide();
11707 if(this.tickable && this.editable){
11713 Roo.log(this.store.reader.jsonData);
11714 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11716 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11722 onTypeAhead : function(){
11723 if(this.store.getCount() > 0){
11724 var r = this.store.getAt(0);
11725 var newValue = r.data[this.displayField];
11726 var len = newValue.length;
11727 var selStart = this.getRawValue().length;
11729 if(selStart != len){
11730 this.setRawValue(newValue);
11731 this.selectText(selStart, newValue.length);
11737 onSelect : function(record, index){
11739 if(this.fireEvent('beforeselect', this, record, index) !== false){
11741 this.setFromData(index > -1 ? record.data : false);
11744 this.fireEvent('select', this, record, index);
11749 * Returns the currently selected field value or empty string if no value is set.
11750 * @return {String} value The selected value
11752 getValue : function(){
11755 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11758 if(this.valueField){
11759 return typeof this.value != 'undefined' ? this.value : '';
11761 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11766 * Clears any text/value currently set in the field
11768 clearValue : function(){
11769 if(this.hiddenField){
11770 this.hiddenField.dom.value = '';
11773 this.setRawValue('');
11774 this.lastSelectionText = '';
11775 this.lastData = false;
11780 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11781 * will be displayed in the field. If the value does not match the data value of an existing item,
11782 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11783 * Otherwise the field will be blank (although the value will still be set).
11784 * @param {String} value The value to match
11786 setValue : function(v){
11793 if(this.valueField){
11794 var r = this.findRecord(this.valueField, v);
11796 text = r.data[this.displayField];
11797 }else if(this.valueNotFoundText !== undefined){
11798 text = this.valueNotFoundText;
11801 this.lastSelectionText = text;
11802 if(this.hiddenField){
11803 this.hiddenField.dom.value = v;
11805 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11809 * @property {Object} the last set data for the element
11814 * Sets the value of the field based on a object which is related to the record format for the store.
11815 * @param {Object} value the value to set as. or false on reset?
11817 setFromData : function(o){
11824 var dv = ''; // display value
11825 var vv = ''; // value value..
11827 if (this.displayField) {
11828 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11830 // this is an error condition!!!
11831 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11834 if(this.valueField){
11835 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11838 if(this.hiddenField){
11839 this.hiddenField.dom.value = vv;
11841 this.lastSelectionText = dv;
11842 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11846 // no hidden field.. - we store the value in 'value', but still display
11847 // display field!!!!
11848 this.lastSelectionText = dv;
11849 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11855 reset : function(){
11856 // overridden so that last data is reset..
11863 this.setValue(this.originalValue);
11864 this.clearInvalid();
11865 this.lastData = false;
11867 this.view.clearSelections();
11871 findRecord : function(prop, value){
11873 if(this.store.getCount() > 0){
11874 this.store.each(function(r){
11875 if(r.data[prop] == value){
11885 getName: function()
11887 // returns hidden if it's set..
11888 if (!this.rendered) {return ''};
11889 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11893 onViewMove : function(e, t){
11894 this.inKeyMode = false;
11898 onViewOver : function(e, t){
11899 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11902 var item = this.view.findItemFromChild(t);
11905 var index = this.view.indexOf(item);
11906 this.select(index, false);
11911 onViewClick : function(view, doFocus, el, e)
11913 var index = this.view.getSelectedIndexes()[0];
11915 var r = this.store.getAt(index);
11919 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11926 Roo.each(this.tickItems, function(v,k){
11928 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11929 _this.tickItems.splice(k, 1);
11931 if(typeof(e) == 'undefined' && view == false){
11932 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11944 this.tickItems.push(r.data);
11946 if(typeof(e) == 'undefined' && view == false){
11947 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11954 this.onSelect(r, index);
11956 if(doFocus !== false && !this.blockFocus){
11957 this.inputEl().focus();
11962 restrictHeight : function(){
11963 //this.innerList.dom.style.height = '';
11964 //var inner = this.innerList.dom;
11965 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11966 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11967 //this.list.beginUpdate();
11968 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11969 this.list.alignTo(this.inputEl(), this.listAlign);
11970 this.list.alignTo(this.inputEl(), this.listAlign);
11971 //this.list.endUpdate();
11975 onEmptyResults : function(){
11977 if(this.tickable && this.editable){
11978 this.restrictHeight();
11986 * Returns true if the dropdown list is expanded, else false.
11988 isExpanded : function(){
11989 return this.list.isVisible();
11993 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11994 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11995 * @param {String} value The data value of the item to select
11996 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11997 * selected item if it is not currently in view (defaults to true)
11998 * @return {Boolean} True if the value matched an item in the list, else false
12000 selectByValue : function(v, scrollIntoView){
12001 if(v !== undefined && v !== null){
12002 var r = this.findRecord(this.valueField || this.displayField, v);
12004 this.select(this.store.indexOf(r), scrollIntoView);
12012 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12013 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12014 * @param {Number} index The zero-based index of the list item to select
12015 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12016 * selected item if it is not currently in view (defaults to true)
12018 select : function(index, scrollIntoView){
12019 this.selectedIndex = index;
12020 this.view.select(index);
12021 if(scrollIntoView !== false){
12022 var el = this.view.getNode(index);
12024 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12027 this.list.scrollChildIntoView(el, false);
12033 selectNext : function(){
12034 var ct = this.store.getCount();
12036 if(this.selectedIndex == -1){
12038 }else if(this.selectedIndex < ct-1){
12039 this.select(this.selectedIndex+1);
12045 selectPrev : function(){
12046 var ct = this.store.getCount();
12048 if(this.selectedIndex == -1){
12050 }else if(this.selectedIndex != 0){
12051 this.select(this.selectedIndex-1);
12057 onKeyUp : function(e){
12058 if(this.editable !== false && !e.isSpecialKey()){
12059 this.lastKey = e.getKey();
12060 this.dqTask.delay(this.queryDelay);
12065 validateBlur : function(){
12066 return !this.list || !this.list.isVisible();
12070 initQuery : function(){
12072 var v = this.getRawValue();
12074 if(this.tickable && this.editable){
12075 v = this.tickableInputEl().getValue();
12082 doForce : function(){
12083 if(this.inputEl().dom.value.length > 0){
12084 this.inputEl().dom.value =
12085 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12091 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12092 * query allowing the query action to be canceled if needed.
12093 * @param {String} query The SQL query to execute
12094 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12095 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12096 * saved in the current store (defaults to false)
12098 doQuery : function(q, forceAll){
12100 if(q === undefined || q === null){
12105 forceAll: forceAll,
12109 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12114 forceAll = qe.forceAll;
12115 if(forceAll === true || (q.length >= this.minChars)){
12117 this.hasQuery = true;
12119 if(this.lastQuery != q || this.alwaysQuery){
12120 this.lastQuery = q;
12121 if(this.mode == 'local'){
12122 this.selectedIndex = -1;
12124 this.store.clearFilter();
12127 if(this.specialFilter){
12128 this.fireEvent('specialfilter', this);
12133 this.store.filter(this.displayField, q);
12136 this.store.fireEvent("datachanged", this.store);
12143 this.store.baseParams[this.queryParam] = q;
12145 var options = {params : this.getParams(q)};
12148 options.add = true;
12149 options.params.start = this.page * this.pageSize;
12152 this.store.load(options);
12155 * this code will make the page width larger, at the beginning, the list not align correctly,
12156 * we should expand the list on onLoad
12157 * so command out it
12162 this.selectedIndex = -1;
12167 this.loadNext = false;
12171 getParams : function(q){
12173 //p[this.queryParam] = q;
12177 p.limit = this.pageSize;
12183 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12185 collapse : function(){
12186 if(!this.isExpanded()){
12193 this.hasFocus = false;
12195 this.cancelBtn.hide();
12196 this.trigger.show();
12199 this.tickableInputEl().dom.value = '';
12200 this.tickableInputEl().blur();
12205 Roo.get(document).un('mousedown', this.collapseIf, this);
12206 Roo.get(document).un('mousewheel', this.collapseIf, this);
12207 if (!this.editable) {
12208 Roo.get(document).un('keydown', this.listKeyPress, this);
12210 this.fireEvent('collapse', this);
12214 collapseIf : function(e){
12215 var in_combo = e.within(this.el);
12216 var in_list = e.within(this.list);
12217 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12219 if (in_combo || in_list || is_list) {
12220 //e.stopPropagation();
12225 this.onTickableFooterButtonClick(e, false, false);
12233 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12235 expand : function(){
12237 if(this.isExpanded() || !this.hasFocus){
12241 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12242 this.list.setWidth(lw);
12249 this.restrictHeight();
12253 this.tickItems = Roo.apply([], this.item);
12256 this.cancelBtn.show();
12257 this.trigger.hide();
12260 this.tickableInputEl().focus();
12265 Roo.get(document).on('mousedown', this.collapseIf, this);
12266 Roo.get(document).on('mousewheel', this.collapseIf, this);
12267 if (!this.editable) {
12268 Roo.get(document).on('keydown', this.listKeyPress, this);
12271 this.fireEvent('expand', this);
12275 // Implements the default empty TriggerField.onTriggerClick function
12276 onTriggerClick : function(e)
12278 Roo.log('trigger click');
12280 if(this.disabled || !this.triggerList){
12285 this.loadNext = false;
12287 if(this.isExpanded()){
12289 if (!this.blockFocus) {
12290 this.inputEl().focus();
12294 this.hasFocus = true;
12295 if(this.triggerAction == 'all') {
12296 this.doQuery(this.allQuery, true);
12298 this.doQuery(this.getRawValue());
12300 if (!this.blockFocus) {
12301 this.inputEl().focus();
12306 onTickableTriggerClick : function(e)
12313 this.loadNext = false;
12314 this.hasFocus = true;
12316 if(this.triggerAction == 'all') {
12317 this.doQuery(this.allQuery, true);
12319 this.doQuery(this.getRawValue());
12323 onSearchFieldClick : function(e)
12325 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12326 this.onTickableFooterButtonClick(e, false, false);
12330 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12335 this.loadNext = false;
12336 this.hasFocus = true;
12338 if(this.triggerAction == 'all') {
12339 this.doQuery(this.allQuery, true);
12341 this.doQuery(this.getRawValue());
12345 listKeyPress : function(e)
12347 //Roo.log('listkeypress');
12348 // scroll to first matching element based on key pres..
12349 if (e.isSpecialKey()) {
12352 var k = String.fromCharCode(e.getKey()).toUpperCase();
12355 var csel = this.view.getSelectedNodes();
12356 var cselitem = false;
12358 var ix = this.view.indexOf(csel[0]);
12359 cselitem = this.store.getAt(ix);
12360 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12366 this.store.each(function(v) {
12368 // start at existing selection.
12369 if (cselitem.id == v.id) {
12375 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12376 match = this.store.indexOf(v);
12382 if (match === false) {
12383 return true; // no more action?
12386 this.view.select(match);
12387 var sn = Roo.get(this.view.getSelectedNodes()[0])
12388 sn.scrollIntoView(sn.dom.parentNode, false);
12391 onViewScroll : function(e, t){
12393 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
12397 this.hasQuery = true;
12399 this.loading = this.list.select('.loading', true).first();
12401 if(this.loading === null){
12402 this.list.createChild({
12404 cls: 'loading select2-more-results select2-active',
12405 html: 'Loading more results...'
12408 this.loading = this.list.select('.loading', true).first();
12410 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12412 this.loading.hide();
12415 this.loading.show();
12420 this.loadNext = true;
12422 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12427 addItem : function(o)
12429 var dv = ''; // display value
12431 if (this.displayField) {
12432 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12434 // this is an error condition!!!
12435 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12442 var choice = this.choices.createChild({
12444 cls: 'select2-search-choice',
12453 cls: 'select2-search-choice-close',
12458 }, this.searchField);
12460 var close = choice.select('a.select2-search-choice-close', true).first()
12462 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12470 this.inputEl().dom.value = '';
12475 onRemoveItem : function(e, _self, o)
12477 e.preventDefault();
12479 this.lastItem = Roo.apply([], this.item);
12481 var index = this.item.indexOf(o.data) * 1;
12484 Roo.log('not this item?!');
12488 this.item.splice(index, 1);
12493 this.fireEvent('remove', this, e);
12499 syncValue : function()
12501 if(!this.item.length){
12508 Roo.each(this.item, function(i){
12509 if(_this.valueField){
12510 value.push(i[_this.valueField]);
12517 this.value = value.join(',');
12519 if(this.hiddenField){
12520 this.hiddenField.dom.value = this.value;
12523 this.store.fireEvent("datachanged", this.store);
12526 clearItem : function()
12528 if(!this.multiple){
12534 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12543 inputEl: function ()
12546 return this.searchField;
12548 return this.el.select('input.form-control',true).first();
12552 onTickableFooterButtonClick : function(e, btn, el)
12554 e.preventDefault();
12556 this.lastItem = Roo.apply([], this.item);
12558 if(btn && btn.name == 'cancel'){
12559 this.tickItems = Roo.apply([], this.item);
12568 Roo.each(this.tickItems, function(o){
12576 validate : function()
12578 var v = this.getRawValue();
12581 v = this.getValue();
12584 if(this.disabled || this.allowBlank || v.length){
12589 this.markInvalid();
12593 tickableInputEl : function()
12595 if(!this.tickable || !this.editable){
12596 return this.inputEl();
12599 return this.inputEl().select('.select2-search-field-input', true).first();
12605 * @cfg {Boolean} grow
12609 * @cfg {Number} growMin
12613 * @cfg {Number} growMax
12623 * Ext JS Library 1.1.1
12624 * Copyright(c) 2006-2007, Ext JS, LLC.
12626 * Originally Released Under LGPL - original licence link has changed is not relivant.
12629 * <script type="text/javascript">
12634 * @extends Roo.util.Observable
12635 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12636 * This class also supports single and multi selection modes. <br>
12637 * Create a data model bound view:
12639 var store = new Roo.data.Store(...);
12641 var view = new Roo.View({
12643 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12645 singleSelect: true,
12646 selectedClass: "ydataview-selected",
12650 // listen for node click?
12651 view.on("click", function(vw, index, node, e){
12652 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12656 dataModel.load("foobar.xml");
12658 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12660 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12661 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12663 * Note: old style constructor is still suported (container, template, config)
12666 * Create a new View
12667 * @param {Object} config The config object
12670 Roo.View = function(config, depreciated_tpl, depreciated_config){
12672 this.parent = false;
12674 if (typeof(depreciated_tpl) == 'undefined') {
12675 // new way.. - universal constructor.
12676 Roo.apply(this, config);
12677 this.el = Roo.get(this.el);
12680 this.el = Roo.get(config);
12681 this.tpl = depreciated_tpl;
12682 Roo.apply(this, depreciated_config);
12684 this.wrapEl = this.el.wrap().wrap();
12685 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12688 if(typeof(this.tpl) == "string"){
12689 this.tpl = new Roo.Template(this.tpl);
12691 // support xtype ctors..
12692 this.tpl = new Roo.factory(this.tpl, Roo);
12696 this.tpl.compile();
12701 * @event beforeclick
12702 * Fires before a click is processed. Returns false to cancel the default action.
12703 * @param {Roo.View} this
12704 * @param {Number} index The index of the target node
12705 * @param {HTMLElement} node The target node
12706 * @param {Roo.EventObject} e The raw event object
12708 "beforeclick" : true,
12711 * Fires when a template node is clicked.
12712 * @param {Roo.View} this
12713 * @param {Number} index The index of the target node
12714 * @param {HTMLElement} node The target node
12715 * @param {Roo.EventObject} e The raw event object
12720 * Fires when a template node is double clicked.
12721 * @param {Roo.View} this
12722 * @param {Number} index The index of the target node
12723 * @param {HTMLElement} node The target node
12724 * @param {Roo.EventObject} e The raw event object
12728 * @event contextmenu
12729 * Fires when a template node is right clicked.
12730 * @param {Roo.View} this
12731 * @param {Number} index The index of the target node
12732 * @param {HTMLElement} node The target node
12733 * @param {Roo.EventObject} e The raw event object
12735 "contextmenu" : true,
12737 * @event selectionchange
12738 * Fires when the selected nodes change.
12739 * @param {Roo.View} this
12740 * @param {Array} selections Array of the selected nodes
12742 "selectionchange" : true,
12745 * @event beforeselect
12746 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12747 * @param {Roo.View} this
12748 * @param {HTMLElement} node The node to be selected
12749 * @param {Array} selections Array of currently selected nodes
12751 "beforeselect" : true,
12753 * @event preparedata
12754 * Fires on every row to render, to allow you to change the data.
12755 * @param {Roo.View} this
12756 * @param {Object} data to be rendered (change this)
12758 "preparedata" : true
12766 "click": this.onClick,
12767 "dblclick": this.onDblClick,
12768 "contextmenu": this.onContextMenu,
12772 this.selections = [];
12774 this.cmp = new Roo.CompositeElementLite([]);
12776 this.store = Roo.factory(this.store, Roo.data);
12777 this.setStore(this.store, true);
12780 if ( this.footer && this.footer.xtype) {
12782 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12784 this.footer.dataSource = this.store
12785 this.footer.container = fctr;
12786 this.footer = Roo.factory(this.footer, Roo);
12787 fctr.insertFirst(this.el);
12789 // this is a bit insane - as the paging toolbar seems to detach the el..
12790 // dom.parentNode.parentNode.parentNode
12791 // they get detached?
12795 Roo.View.superclass.constructor.call(this);
12800 Roo.extend(Roo.View, Roo.util.Observable, {
12803 * @cfg {Roo.data.Store} store Data store to load data from.
12808 * @cfg {String|Roo.Element} el The container element.
12813 * @cfg {String|Roo.Template} tpl The template used by this View
12817 * @cfg {String} dataName the named area of the template to use as the data area
12818 * Works with domtemplates roo-name="name"
12822 * @cfg {String} selectedClass The css class to add to selected nodes
12824 selectedClass : "x-view-selected",
12826 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12831 * @cfg {String} text to display on mask (default Loading)
12835 * @cfg {Boolean} multiSelect Allow multiple selection
12837 multiSelect : false,
12839 * @cfg {Boolean} singleSelect Allow single selection
12841 singleSelect: false,
12844 * @cfg {Boolean} toggleSelect - selecting
12846 toggleSelect : false,
12849 * @cfg {Boolean} tickable - selecting
12854 * Returns the element this view is bound to.
12855 * @return {Roo.Element}
12857 getEl : function(){
12858 return this.wrapEl;
12864 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12866 refresh : function(){
12867 //Roo.log('refresh');
12870 // if we are using something like 'domtemplate', then
12871 // the what gets used is:
12872 // t.applySubtemplate(NAME, data, wrapping data..)
12873 // the outer template then get' applied with
12874 // the store 'extra data'
12875 // and the body get's added to the
12876 // roo-name="data" node?
12877 // <span class='roo-tpl-{name}'></span> ?????
12881 this.clearSelections();
12882 this.el.update("");
12884 var records = this.store.getRange();
12885 if(records.length < 1) {
12887 // is this valid?? = should it render a template??
12889 this.el.update(this.emptyText);
12893 if (this.dataName) {
12894 this.el.update(t.apply(this.store.meta)); //????
12895 el = this.el.child('.roo-tpl-' + this.dataName);
12898 for(var i = 0, len = records.length; i < len; i++){
12899 var data = this.prepareData(records[i].data, i, records[i]);
12900 this.fireEvent("preparedata", this, data, i, records[i]);
12902 var d = Roo.apply({}, data);
12905 Roo.apply(d, {'roo-id' : Roo.id()});
12909 Roo.each(this.parent.item, function(item){
12910 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12913 Roo.apply(d, {'roo-data-checked' : 'checked'});
12917 html[html.length] = Roo.util.Format.trim(
12919 t.applySubtemplate(this.dataName, d, this.store.meta) :
12926 el.update(html.join(""));
12927 this.nodes = el.dom.childNodes;
12928 this.updateIndexes(0);
12933 * Function to override to reformat the data that is sent to
12934 * the template for each node.
12935 * DEPRICATED - use the preparedata event handler.
12936 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12937 * a JSON object for an UpdateManager bound view).
12939 prepareData : function(data, index, record)
12941 this.fireEvent("preparedata", this, data, index, record);
12945 onUpdate : function(ds, record){
12946 // Roo.log('on update');
12947 this.clearSelections();
12948 var index = this.store.indexOf(record);
12949 var n = this.nodes[index];
12950 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12951 n.parentNode.removeChild(n);
12952 this.updateIndexes(index, index);
12958 onAdd : function(ds, records, index)
12960 //Roo.log(['on Add', ds, records, index] );
12961 this.clearSelections();
12962 if(this.nodes.length == 0){
12966 var n = this.nodes[index];
12967 for(var i = 0, len = records.length; i < len; i++){
12968 var d = this.prepareData(records[i].data, i, records[i]);
12970 this.tpl.insertBefore(n, d);
12973 this.tpl.append(this.el, d);
12976 this.updateIndexes(index);
12979 onRemove : function(ds, record, index){
12980 // Roo.log('onRemove');
12981 this.clearSelections();
12982 var el = this.dataName ?
12983 this.el.child('.roo-tpl-' + this.dataName) :
12986 el.dom.removeChild(this.nodes[index]);
12987 this.updateIndexes(index);
12991 * Refresh an individual node.
12992 * @param {Number} index
12994 refreshNode : function(index){
12995 this.onUpdate(this.store, this.store.getAt(index));
12998 updateIndexes : function(startIndex, endIndex){
12999 var ns = this.nodes;
13000 startIndex = startIndex || 0;
13001 endIndex = endIndex || ns.length - 1;
13002 for(var i = startIndex; i <= endIndex; i++){
13003 ns[i].nodeIndex = i;
13008 * Changes the data store this view uses and refresh the view.
13009 * @param {Store} store
13011 setStore : function(store, initial){
13012 if(!initial && this.store){
13013 this.store.un("datachanged", this.refresh);
13014 this.store.un("add", this.onAdd);
13015 this.store.un("remove", this.onRemove);
13016 this.store.un("update", this.onUpdate);
13017 this.store.un("clear", this.refresh);
13018 this.store.un("beforeload", this.onBeforeLoad);
13019 this.store.un("load", this.onLoad);
13020 this.store.un("loadexception", this.onLoad);
13024 store.on("datachanged", this.refresh, this);
13025 store.on("add", this.onAdd, this);
13026 store.on("remove", this.onRemove, this);
13027 store.on("update", this.onUpdate, this);
13028 store.on("clear", this.refresh, this);
13029 store.on("beforeload", this.onBeforeLoad, this);
13030 store.on("load", this.onLoad, this);
13031 store.on("loadexception", this.onLoad, this);
13039 * onbeforeLoad - masks the loading area.
13042 onBeforeLoad : function(store,opts)
13044 //Roo.log('onBeforeLoad');
13046 this.el.update("");
13048 this.el.mask(this.mask ? this.mask : "Loading" );
13050 onLoad : function ()
13057 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13058 * @param {HTMLElement} node
13059 * @return {HTMLElement} The template node
13061 findItemFromChild : function(node){
13062 var el = this.dataName ?
13063 this.el.child('.roo-tpl-' + this.dataName,true) :
13066 if(!node || node.parentNode == el){
13069 var p = node.parentNode;
13070 while(p && p != el){
13071 if(p.parentNode == el){
13080 onClick : function(e){
13081 var item = this.findItemFromChild(e.getTarget());
13083 var index = this.indexOf(item);
13084 if(this.onItemClick(item, index, e) !== false){
13085 this.fireEvent("click", this, index, item, e);
13088 this.clearSelections();
13093 onContextMenu : function(e){
13094 var item = this.findItemFromChild(e.getTarget());
13096 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13101 onDblClick : function(e){
13102 var item = this.findItemFromChild(e.getTarget());
13104 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13108 onItemClick : function(item, index, e)
13110 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13113 if (this.toggleSelect) {
13114 var m = this.isSelected(item) ? 'unselect' : 'select';
13117 _t[m](item, true, false);
13120 if(this.multiSelect || this.singleSelect){
13121 if(this.multiSelect && e.shiftKey && this.lastSelection){
13122 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13124 this.select(item, this.multiSelect && e.ctrlKey);
13125 this.lastSelection = item;
13128 if(!this.tickable){
13129 e.preventDefault();
13137 * Get the number of selected nodes.
13140 getSelectionCount : function(){
13141 return this.selections.length;
13145 * Get the currently selected nodes.
13146 * @return {Array} An array of HTMLElements
13148 getSelectedNodes : function(){
13149 return this.selections;
13153 * Get the indexes of the selected nodes.
13156 getSelectedIndexes : function(){
13157 var indexes = [], s = this.selections;
13158 for(var i = 0, len = s.length; i < len; i++){
13159 indexes.push(s[i].nodeIndex);
13165 * Clear all selections
13166 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13168 clearSelections : function(suppressEvent){
13169 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13170 this.cmp.elements = this.selections;
13171 this.cmp.removeClass(this.selectedClass);
13172 this.selections = [];
13173 if(!suppressEvent){
13174 this.fireEvent("selectionchange", this, this.selections);
13180 * Returns true if the passed node is selected
13181 * @param {HTMLElement/Number} node The node or node index
13182 * @return {Boolean}
13184 isSelected : function(node){
13185 var s = this.selections;
13189 node = this.getNode(node);
13190 return s.indexOf(node) !== -1;
13195 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
13196 * @param {Boolean} keepExisting (optional) true to keep existing selections
13197 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13199 select : function(nodeInfo, keepExisting, suppressEvent){
13200 if(nodeInfo instanceof Array){
13202 this.clearSelections(true);
13204 for(var i = 0, len = nodeInfo.length; i < len; i++){
13205 this.select(nodeInfo[i], true, true);
13209 var node = this.getNode(nodeInfo);
13210 if(!node || this.isSelected(node)){
13211 return; // already selected.
13214 this.clearSelections(true);
13217 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13218 Roo.fly(node).addClass(this.selectedClass);
13219 this.selections.push(node);
13220 if(!suppressEvent){
13221 this.fireEvent("selectionchange", this, this.selections);
13229 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
13230 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13231 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13233 unselect : function(nodeInfo, keepExisting, suppressEvent)
13235 if(nodeInfo instanceof Array){
13236 Roo.each(this.selections, function(s) {
13237 this.unselect(s, nodeInfo);
13241 var node = this.getNode(nodeInfo);
13242 if(!node || !this.isSelected(node)){
13243 //Roo.log("not selected");
13244 return; // not selected.
13248 Roo.each(this.selections, function(s) {
13250 Roo.fly(node).removeClass(this.selectedClass);
13257 this.selections= ns;
13258 this.fireEvent("selectionchange", this, this.selections);
13262 * Gets a template node.
13263 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13264 * @return {HTMLElement} The node or null if it wasn't found
13266 getNode : function(nodeInfo){
13267 if(typeof nodeInfo == "string"){
13268 return document.getElementById(nodeInfo);
13269 }else if(typeof nodeInfo == "number"){
13270 return this.nodes[nodeInfo];
13276 * Gets a range template nodes.
13277 * @param {Number} startIndex
13278 * @param {Number} endIndex
13279 * @return {Array} An array of nodes
13281 getNodes : function(start, end){
13282 var ns = this.nodes;
13283 start = start || 0;
13284 end = typeof end == "undefined" ? ns.length - 1 : end;
13287 for(var i = start; i <= end; i++){
13291 for(var i = start; i >= end; i--){
13299 * Finds the index of the passed node
13300 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13301 * @return {Number} The index of the node or -1
13303 indexOf : function(node){
13304 node = this.getNode(node);
13305 if(typeof node.nodeIndex == "number"){
13306 return node.nodeIndex;
13308 var ns = this.nodes;
13309 for(var i = 0, len = ns.length; i < len; i++){
13320 * based on jquery fullcalendar
13324 Roo.bootstrap = Roo.bootstrap || {};
13326 * @class Roo.bootstrap.Calendar
13327 * @extends Roo.bootstrap.Component
13328 * Bootstrap Calendar class
13329 * @cfg {Boolean} loadMask (true|false) default false
13330 * @cfg {Object} header generate the user specific header of the calendar, default false
13333 * Create a new Container
13334 * @param {Object} config The config object
13339 Roo.bootstrap.Calendar = function(config){
13340 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13344 * Fires when a date is selected
13345 * @param {DatePicker} this
13346 * @param {Date} date The selected date
13350 * @event monthchange
13351 * Fires when the displayed month changes
13352 * @param {DatePicker} this
13353 * @param {Date} date The selected month
13355 'monthchange': true,
13357 * @event evententer
13358 * Fires when mouse over an event
13359 * @param {Calendar} this
13360 * @param {event} Event
13362 'evententer': true,
13364 * @event eventleave
13365 * Fires when the mouse leaves an
13366 * @param {Calendar} this
13369 'eventleave': true,
13371 * @event eventclick
13372 * Fires when the mouse click an
13373 * @param {Calendar} this
13382 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13385 * @cfg {Number} startDay
13386 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13394 getAutoCreate : function(){
13397 var fc_button = function(name, corner, style, content ) {
13398 return Roo.apply({},{
13400 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13402 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13405 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13416 style : 'width:100%',
13423 cls : 'fc-header-left',
13425 fc_button('prev', 'left', 'arrow', '‹' ),
13426 fc_button('next', 'right', 'arrow', '›' ),
13427 { tag: 'span', cls: 'fc-header-space' },
13428 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13436 cls : 'fc-header-center',
13440 cls: 'fc-header-title',
13443 html : 'month / year'
13451 cls : 'fc-header-right',
13453 /* fc_button('month', 'left', '', 'month' ),
13454 fc_button('week', '', '', 'week' ),
13455 fc_button('day', 'right', '', 'day' )
13467 header = this.header;
13470 var cal_heads = function() {
13472 // fixme - handle this.
13474 for (var i =0; i < Date.dayNames.length; i++) {
13475 var d = Date.dayNames[i];
13478 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13479 html : d.substring(0,3)
13483 ret[0].cls += ' fc-first';
13484 ret[6].cls += ' fc-last';
13487 var cal_cell = function(n) {
13490 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13495 cls: 'fc-day-number',
13499 cls: 'fc-day-content',
13503 style: 'position: relative;' // height: 17px;
13515 var cal_rows = function() {
13518 for (var r = 0; r < 6; r++) {
13525 for (var i =0; i < Date.dayNames.length; i++) {
13526 var d = Date.dayNames[i];
13527 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13530 row.cn[0].cls+=' fc-first';
13531 row.cn[0].cn[0].style = 'min-height:90px';
13532 row.cn[6].cls+=' fc-last';
13536 ret[0].cls += ' fc-first';
13537 ret[4].cls += ' fc-prev-last';
13538 ret[5].cls += ' fc-last';
13545 cls: 'fc-border-separate',
13546 style : 'width:100%',
13554 cls : 'fc-first fc-last',
13572 cls : 'fc-content',
13573 style : "position: relative;",
13576 cls : 'fc-view fc-view-month fc-grid',
13577 style : 'position: relative',
13578 unselectable : 'on',
13581 cls : 'fc-event-container',
13582 style : 'position:absolute;z-index:8;top:0;left:0;'
13600 initEvents : function()
13603 throw "can not find store for calendar";
13609 style: "text-align:center",
13613 style: "background-color:white;width:50%;margin:250 auto",
13617 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13628 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13630 var size = this.el.select('.fc-content', true).first().getSize();
13631 this.maskEl.setSize(size.width, size.height);
13632 this.maskEl.enableDisplayMode("block");
13633 if(!this.loadMask){
13634 this.maskEl.hide();
13637 this.store = Roo.factory(this.store, Roo.data);
13638 this.store.on('load', this.onLoad, this);
13639 this.store.on('beforeload', this.onBeforeLoad, this);
13643 this.cells = this.el.select('.fc-day',true);
13644 //Roo.log(this.cells);
13645 this.textNodes = this.el.query('.fc-day-number');
13646 this.cells.addClassOnOver('fc-state-hover');
13648 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13649 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13650 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13651 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13653 this.on('monthchange', this.onMonthChange, this);
13655 this.update(new Date().clearTime());
13658 resize : function() {
13659 var sz = this.el.getSize();
13661 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13662 this.el.select('.fc-day-content div',true).setHeight(34);
13667 showPrevMonth : function(e){
13668 this.update(this.activeDate.add("mo", -1));
13670 showToday : function(e){
13671 this.update(new Date().clearTime());
13674 showNextMonth : function(e){
13675 this.update(this.activeDate.add("mo", 1));
13679 showPrevYear : function(){
13680 this.update(this.activeDate.add("y", -1));
13684 showNextYear : function(){
13685 this.update(this.activeDate.add("y", 1));
13690 update : function(date)
13692 var vd = this.activeDate;
13693 this.activeDate = date;
13694 // if(vd && this.el){
13695 // var t = date.getTime();
13696 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13697 // Roo.log('using add remove');
13699 // this.fireEvent('monthchange', this, date);
13701 // this.cells.removeClass("fc-state-highlight");
13702 // this.cells.each(function(c){
13703 // if(c.dateValue == t){
13704 // c.addClass("fc-state-highlight");
13705 // setTimeout(function(){
13706 // try{c.dom.firstChild.focus();}catch(e){}
13716 var days = date.getDaysInMonth();
13718 var firstOfMonth = date.getFirstDateOfMonth();
13719 var startingPos = firstOfMonth.getDay()-this.startDay;
13721 if(startingPos < this.startDay){
13725 var pm = date.add(Date.MONTH, -1);
13726 var prevStart = pm.getDaysInMonth()-startingPos;
13728 this.cells = this.el.select('.fc-day',true);
13729 this.textNodes = this.el.query('.fc-day-number');
13730 this.cells.addClassOnOver('fc-state-hover');
13732 var cells = this.cells.elements;
13733 var textEls = this.textNodes;
13735 Roo.each(cells, function(cell){
13736 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13739 days += startingPos;
13741 // convert everything to numbers so it's fast
13742 var day = 86400000;
13743 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13746 //Roo.log(prevStart);
13748 var today = new Date().clearTime().getTime();
13749 var sel = date.clearTime().getTime();
13750 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13751 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13752 var ddMatch = this.disabledDatesRE;
13753 var ddText = this.disabledDatesText;
13754 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13755 var ddaysText = this.disabledDaysText;
13756 var format = this.format;
13758 var setCellClass = function(cal, cell){
13762 //Roo.log('set Cell Class');
13764 var t = d.getTime();
13768 cell.dateValue = t;
13770 cell.className += " fc-today";
13771 cell.className += " fc-state-highlight";
13772 cell.title = cal.todayText;
13775 // disable highlight in other month..
13776 //cell.className += " fc-state-highlight";
13781 cell.className = " fc-state-disabled";
13782 cell.title = cal.minText;
13786 cell.className = " fc-state-disabled";
13787 cell.title = cal.maxText;
13791 if(ddays.indexOf(d.getDay()) != -1){
13792 cell.title = ddaysText;
13793 cell.className = " fc-state-disabled";
13796 if(ddMatch && format){
13797 var fvalue = d.dateFormat(format);
13798 if(ddMatch.test(fvalue)){
13799 cell.title = ddText.replace("%0", fvalue);
13800 cell.className = " fc-state-disabled";
13804 if (!cell.initialClassName) {
13805 cell.initialClassName = cell.dom.className;
13808 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13813 for(; i < startingPos; i++) {
13814 textEls[i].innerHTML = (++prevStart);
13815 d.setDate(d.getDate()+1);
13817 cells[i].className = "fc-past fc-other-month";
13818 setCellClass(this, cells[i]);
13823 for(; i < days; i++){
13824 intDay = i - startingPos + 1;
13825 textEls[i].innerHTML = (intDay);
13826 d.setDate(d.getDate()+1);
13828 cells[i].className = ''; // "x-date-active";
13829 setCellClass(this, cells[i]);
13833 for(; i < 42; i++) {
13834 textEls[i].innerHTML = (++extraDays);
13835 d.setDate(d.getDate()+1);
13837 cells[i].className = "fc-future fc-other-month";
13838 setCellClass(this, cells[i]);
13841 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13843 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13845 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13846 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13848 if(totalRows != 6){
13849 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13850 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13853 this.fireEvent('monthchange', this, date);
13857 if(!this.internalRender){
13858 var main = this.el.dom.firstChild;
13859 var w = main.offsetWidth;
13860 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13861 Roo.fly(main).setWidth(w);
13862 this.internalRender = true;
13863 // opera does not respect the auto grow header center column
13864 // then, after it gets a width opera refuses to recalculate
13865 // without a second pass
13866 if(Roo.isOpera && !this.secondPass){
13867 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13868 this.secondPass = true;
13869 this.update.defer(10, this, [date]);
13876 findCell : function(dt) {
13877 dt = dt.clearTime().getTime();
13879 this.cells.each(function(c){
13880 //Roo.log("check " +c.dateValue + '?=' + dt);
13881 if(c.dateValue == dt){
13891 findCells : function(ev) {
13892 var s = ev.start.clone().clearTime().getTime();
13894 var e= ev.end.clone().clearTime().getTime();
13897 this.cells.each(function(c){
13898 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13900 if(c.dateValue > e){
13903 if(c.dateValue < s){
13912 // findBestRow: function(cells)
13916 // for (var i =0 ; i < cells.length;i++) {
13917 // ret = Math.max(cells[i].rows || 0,ret);
13924 addItem : function(ev)
13926 // look for vertical location slot in
13927 var cells = this.findCells(ev);
13929 // ev.row = this.findBestRow(cells);
13931 // work out the location.
13935 for(var i =0; i < cells.length; i++) {
13937 cells[i].row = cells[0].row;
13940 cells[i].row = cells[i].row + 1;
13950 if (crow.start.getY() == cells[i].getY()) {
13952 crow.end = cells[i];
13969 cells[0].events.push(ev);
13971 this.calevents.push(ev);
13974 clearEvents: function() {
13976 if(!this.calevents){
13980 Roo.each(this.cells.elements, function(c){
13986 Roo.each(this.calevents, function(e) {
13987 Roo.each(e.els, function(el) {
13988 el.un('mouseenter' ,this.onEventEnter, this);
13989 el.un('mouseleave' ,this.onEventLeave, this);
13994 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14000 renderEvents: function()
14004 this.cells.each(function(c) {
14013 if(c.row != c.events.length){
14014 r = 4 - (4 - (c.row - c.events.length));
14017 c.events = ev.slice(0, r);
14018 c.more = ev.slice(r);
14020 if(c.more.length && c.more.length == 1){
14021 c.events.push(c.more.pop());
14024 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14028 this.cells.each(function(c) {
14030 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14033 for (var e = 0; e < c.events.length; e++){
14034 var ev = c.events[e];
14035 var rows = ev.rows;
14037 for(var i = 0; i < rows.length; i++) {
14039 // how many rows should it span..
14042 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14043 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14045 unselectable : "on",
14048 cls: 'fc-event-inner',
14052 // cls: 'fc-event-time',
14053 // html : cells.length > 1 ? '' : ev.time
14057 cls: 'fc-event-title',
14058 html : String.format('{0}', ev.title)
14065 cls: 'ui-resizable-handle ui-resizable-e',
14066 html : '  '
14073 cfg.cls += ' fc-event-start';
14075 if ((i+1) == rows.length) {
14076 cfg.cls += ' fc-event-end';
14079 var ctr = _this.el.select('.fc-event-container',true).first();
14080 var cg = ctr.createChild(cfg);
14082 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14083 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14085 var r = (c.more.length) ? 1 : 0;
14086 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14087 cg.setWidth(ebox.right - sbox.x -2);
14089 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14090 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14091 cg.on('click', _this.onEventClick, _this, ev);
14102 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14103 style : 'position: absolute',
14104 unselectable : "on",
14107 cls: 'fc-event-inner',
14111 cls: 'fc-event-title',
14119 cls: 'ui-resizable-handle ui-resizable-e',
14120 html : '  '
14126 var ctr = _this.el.select('.fc-event-container',true).first();
14127 var cg = ctr.createChild(cfg);
14129 var sbox = c.select('.fc-day-content',true).first().getBox();
14130 var ebox = c.select('.fc-day-content',true).first().getBox();
14132 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14133 cg.setWidth(ebox.right - sbox.x -2);
14135 cg.on('click', _this.onMoreEventClick, _this, c.more);
14145 onEventEnter: function (e, el,event,d) {
14146 this.fireEvent('evententer', this, el, event);
14149 onEventLeave: function (e, el,event,d) {
14150 this.fireEvent('eventleave', this, el, event);
14153 onEventClick: function (e, el,event,d) {
14154 this.fireEvent('eventclick', this, el, event);
14157 onMonthChange: function () {
14161 onMoreEventClick: function(e, el, more)
14165 this.calpopover.placement = 'right';
14166 this.calpopover.setTitle('More');
14168 this.calpopover.setContent('');
14170 var ctr = this.calpopover.el.select('.popover-content', true).first();
14172 Roo.each(more, function(m){
14174 cls : 'fc-event-hori fc-event-draggable',
14177 var cg = ctr.createChild(cfg);
14179 cg.on('click', _this.onEventClick, _this, m);
14182 this.calpopover.show(el);
14187 onLoad: function ()
14189 this.calevents = [];
14192 if(this.store.getCount() > 0){
14193 this.store.data.each(function(d){
14196 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14197 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14198 time : d.data.start_time,
14199 title : d.data.title,
14200 description : d.data.description,
14201 venue : d.data.venue
14206 this.renderEvents();
14208 if(this.calevents.length && this.loadMask){
14209 this.maskEl.hide();
14213 onBeforeLoad: function()
14215 this.clearEvents();
14217 this.maskEl.show();
14231 * @class Roo.bootstrap.Popover
14232 * @extends Roo.bootstrap.Component
14233 * Bootstrap Popover class
14234 * @cfg {String} html contents of the popover (or false to use children..)
14235 * @cfg {String} title of popover (or false to hide)
14236 * @cfg {String} placement how it is placed
14237 * @cfg {String} trigger click || hover (or false to trigger manually)
14238 * @cfg {String} over what (parent or false to trigger manually.)
14239 * @cfg {Number} delay - delay before showing
14242 * Create a new Popover
14243 * @param {Object} config The config object
14246 Roo.bootstrap.Popover = function(config){
14247 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14250 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14252 title: 'Fill in a title',
14255 placement : 'right',
14256 trigger : 'hover', // hover
14262 can_build_overlaid : false,
14264 getChildContainer : function()
14266 return this.el.select('.popover-content',true).first();
14269 getAutoCreate : function(){
14270 Roo.log('make popover?');
14272 cls : 'popover roo-dynamic',
14273 style: 'display:block',
14279 cls : 'popover-inner',
14283 cls: 'popover-title',
14287 cls : 'popover-content',
14298 setTitle: function(str)
14300 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14302 setContent: function(str)
14304 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14306 // as it get's added to the bottom of the page.
14307 onRender : function(ct, position)
14309 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14311 var cfg = Roo.apply({}, this.getAutoCreate());
14315 cfg.cls += ' ' + this.cls;
14318 cfg.style = this.style;
14320 Roo.log("adding to ")
14321 this.el = Roo.get(document.body).createChild(cfg, position);
14327 initEvents : function()
14329 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14330 this.el.enableDisplayMode('block');
14332 if (this.over === false) {
14335 if (this.triggers === false) {
14338 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14339 var triggers = this.trigger ? this.trigger.split(' ') : [];
14340 Roo.each(triggers, function(trigger) {
14342 if (trigger == 'click') {
14343 on_el.on('click', this.toggle, this);
14344 } else if (trigger != 'manual') {
14345 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14346 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14348 on_el.on(eventIn ,this.enter, this);
14349 on_el.on(eventOut, this.leave, this);
14360 toggle : function () {
14361 this.hoverState == 'in' ? this.leave() : this.enter();
14364 enter : function () {
14367 clearTimeout(this.timeout);
14369 this.hoverState = 'in';
14371 if (!this.delay || !this.delay.show) {
14376 this.timeout = setTimeout(function () {
14377 if (_t.hoverState == 'in') {
14380 }, this.delay.show)
14382 leave : function() {
14383 clearTimeout(this.timeout);
14385 this.hoverState = 'out';
14387 if (!this.delay || !this.delay.hide) {
14392 this.timeout = setTimeout(function () {
14393 if (_t.hoverState == 'out') {
14396 }, this.delay.hide)
14399 show : function (on_el)
14402 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14405 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14406 if (this.html !== false) {
14407 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14409 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14410 if (!this.title.length) {
14411 this.el.select('.popover-title',true).hide();
14414 var placement = typeof this.placement == 'function' ?
14415 this.placement.call(this, this.el, on_el) :
14418 var autoToken = /\s?auto?\s?/i;
14419 var autoPlace = autoToken.test(placement);
14421 placement = placement.replace(autoToken, '') || 'top';
14425 //this.el.setXY([0,0]);
14427 this.el.dom.style.display='block';
14428 this.el.addClass(placement);
14430 //this.el.appendTo(on_el);
14432 var p = this.getPosition();
14433 var box = this.el.getBox();
14438 var align = Roo.bootstrap.Popover.alignment[placement];
14439 this.el.alignTo(on_el, align[0],align[1]);
14440 //var arrow = this.el.select('.arrow',true).first();
14441 //arrow.set(align[2],
14443 this.el.addClass('in');
14444 this.hoverState = null;
14446 if (this.el.hasClass('fade')) {
14453 this.el.setXY([0,0]);
14454 this.el.removeClass('in');
14461 Roo.bootstrap.Popover.alignment = {
14462 'left' : ['r-l', [-10,0], 'right'],
14463 'right' : ['l-r', [10,0], 'left'],
14464 'bottom' : ['t-b', [0,10], 'top'],
14465 'top' : [ 'b-t', [0,-10], 'bottom']
14476 * @class Roo.bootstrap.Progress
14477 * @extends Roo.bootstrap.Component
14478 * Bootstrap Progress class
14479 * @cfg {Boolean} striped striped of the progress bar
14480 * @cfg {Boolean} active animated of the progress bar
14484 * Create a new Progress
14485 * @param {Object} config The config object
14488 Roo.bootstrap.Progress = function(config){
14489 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14492 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14497 getAutoCreate : function(){
14505 cfg.cls += ' progress-striped';
14509 cfg.cls += ' active';
14528 * @class Roo.bootstrap.ProgressBar
14529 * @extends Roo.bootstrap.Component
14530 * Bootstrap ProgressBar class
14531 * @cfg {Number} aria_valuenow aria-value now
14532 * @cfg {Number} aria_valuemin aria-value min
14533 * @cfg {Number} aria_valuemax aria-value max
14534 * @cfg {String} label label for the progress bar
14535 * @cfg {String} panel (success | info | warning | danger )
14536 * @cfg {String} role role of the progress bar
14537 * @cfg {String} sr_only text
14541 * Create a new ProgressBar
14542 * @param {Object} config The config object
14545 Roo.bootstrap.ProgressBar = function(config){
14546 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14549 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14553 aria_valuemax : 100,
14559 getAutoCreate : function()
14564 cls: 'progress-bar',
14565 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14577 cfg.role = this.role;
14580 if(this.aria_valuenow){
14581 cfg['aria-valuenow'] = this.aria_valuenow;
14584 if(this.aria_valuemin){
14585 cfg['aria-valuemin'] = this.aria_valuemin;
14588 if(this.aria_valuemax){
14589 cfg['aria-valuemax'] = this.aria_valuemax;
14592 if(this.label && !this.sr_only){
14593 cfg.html = this.label;
14597 cfg.cls += ' progress-bar-' + this.panel;
14603 update : function(aria_valuenow)
14605 this.aria_valuenow = aria_valuenow;
14607 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14622 * @class Roo.bootstrap.TabGroup
14623 * @extends Roo.bootstrap.Column
14624 * Bootstrap Column class
14625 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14626 * @cfg {Boolean} carousel true to make the group behave like a carousel
14627 * @cfg {Number} bullets show the panel pointer.. default 0
14628 * @cfg {Boolena} autoslide (true|false) auto slide .. default false
14629 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14632 * Create a new TabGroup
14633 * @param {Object} config The config object
14636 Roo.bootstrap.TabGroup = function(config){
14637 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14639 this.navId = Roo.id();
14642 Roo.bootstrap.TabGroup.register(this);
14646 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14649 transition : false,
14655 getAutoCreate : function()
14657 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14659 cfg.cls += ' tab-content';
14661 Roo.log('get auto create...............');
14663 if (this.carousel && !Roo.isTouch) {
14664 cfg.cls += ' carousel slide';
14667 cls : 'carousel-inner'
14670 if(this.bullets > 0){
14673 cls : 'carousel-bullets',
14677 if(this.bullets_cls){
14678 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14681 for (var i = 0; i < this.bullets; i++){
14683 cls : 'bullet bullet-' + i
14691 cfg.cn[0].cn = bullets;
14698 initEvents: function()
14700 Roo.log('-------- init events on tab group ---------');
14702 if(this.bullets > 0 && !Roo.isTouch){
14706 if(this.autoslide){
14710 this.slideFn = window.setInterval(function() {
14711 _this.showPanelNext();
14717 getChildContainer : function()
14719 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14723 * register a Navigation item
14724 * @param {Roo.bootstrap.NavItem} the navitem to add
14726 register : function(item)
14728 this.tabs.push( item);
14729 item.navId = this.navId; // not really needed..
14733 getActivePanel : function()
14736 Roo.each(this.tabs, function(t) {
14746 getPanelByName : function(n)
14749 Roo.each(this.tabs, function(t) {
14750 if (t.tabId == n) {
14758 indexOfPanel : function(p)
14761 Roo.each(this.tabs, function(t,i) {
14762 if (t.tabId == p.tabId) {
14771 * show a specific panel
14772 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14773 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14775 showPanel : function (pan)
14777 if(this.transition){
14778 Roo.log("waiting for the transitionend");
14782 if (typeof(pan) == 'number') {
14783 pan = this.tabs[pan];
14785 if (typeof(pan) == 'string') {
14786 pan = this.getPanelByName(pan);
14788 if (pan.tabId == this.getActivePanel().tabId) {
14791 var cur = this.getActivePanel();
14793 if (false === cur.fireEvent('beforedeactivate')) {
14797 if(this.bullets > 0 && !Roo.isTouch){
14798 this.setActiveBullet(this.indexOfPanel(pan));
14801 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14803 this.transition = true;
14804 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14805 var lr = dir == 'next' ? 'left' : 'right';
14806 pan.el.addClass(dir); // or prev
14807 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14808 cur.el.addClass(lr); // or right
14809 pan.el.addClass(lr);
14812 cur.el.on('transitionend', function() {
14813 Roo.log("trans end?");
14815 pan.el.removeClass([lr,dir]);
14816 pan.setActive(true);
14818 cur.el.removeClass([lr]);
14819 cur.setActive(false);
14821 _this.transition = false;
14823 }, this, { single: true } );
14828 cur.setActive(false);
14829 pan.setActive(true);
14834 showPanelNext : function()
14836 var i = this.indexOfPanel(this.getActivePanel());
14838 if (i >= this.tabs.length - 1 && !this.autoslide) {
14842 if (i >= this.tabs.length - 1 && this.autoslide) {
14846 this.showPanel(this.tabs[i+1]);
14849 showPanelPrev : function()
14851 var i = this.indexOfPanel(this.getActivePanel());
14853 if (i < 1 && !this.autoslide) {
14857 if (i < 1 && this.autoslide) {
14858 i = this.tabs.length;
14861 this.showPanel(this.tabs[i-1]);
14864 initBullet : function()
14872 for (var i = 0; i < this.bullets; i++){
14873 var bullet = this.el.select('.bullet-' + i, true).first();
14879 bullet.on('click', (function(e, el, o, ii, t){
14881 e.preventDefault();
14883 _this.showPanel(ii);
14885 if(_this.autoslide && _this.slideFn){
14886 clearInterval(_this.slideFn);
14887 _this.slideFn = window.setInterval(function() {
14888 _this.showPanelNext();
14892 }).createDelegate(this, [i, bullet], true));
14896 setActiveBullet : function(i)
14902 Roo.each(this.el.select('.bullet', true).elements, function(el){
14903 el.removeClass('selected');
14906 var bullet = this.el.select('.bullet-' + i, true).first();
14912 bullet.addClass('selected');
14923 Roo.apply(Roo.bootstrap.TabGroup, {
14927 * register a Navigation Group
14928 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14930 register : function(navgrp)
14932 this.groups[navgrp.navId] = navgrp;
14936 * fetch a Navigation Group based on the navigation ID
14937 * if one does not exist , it will get created.
14938 * @param {string} the navgroup to add
14939 * @returns {Roo.bootstrap.NavGroup} the navgroup
14941 get: function(navId) {
14942 if (typeof(this.groups[navId]) == 'undefined') {
14943 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14945 return this.groups[navId] ;
14960 * @class Roo.bootstrap.TabPanel
14961 * @extends Roo.bootstrap.Component
14962 * Bootstrap TabPanel class
14963 * @cfg {Boolean} active panel active
14964 * @cfg {String} html panel content
14965 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14966 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14970 * Create a new TabPanel
14971 * @param {Object} config The config object
14974 Roo.bootstrap.TabPanel = function(config){
14975 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14979 * Fires when the active status changes
14980 * @param {Roo.bootstrap.TabPanel} this
14981 * @param {Boolean} state the new state
14986 * @event beforedeactivate
14987 * Fires before a tab is de-activated - can be used to do validation on a form.
14988 * @param {Roo.bootstrap.TabPanel} this
14989 * @return {Boolean} false if there is an error
14992 'beforedeactivate': true
14995 this.tabId = this.tabId || Roo.id();
14999 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15006 getAutoCreate : function(){
15009 // item is needed for carousel - not sure if it has any effect otherwise
15010 cls: 'tab-pane item',
15011 html: this.html || ''
15015 cfg.cls += ' active';
15019 cfg.tabId = this.tabId;
15026 initEvents: function()
15028 Roo.log('-------- init events on tab panel ---------');
15030 var p = this.parent();
15031 this.navId = this.navId || p.navId;
15033 if (typeof(this.navId) != 'undefined') {
15034 // not really needed.. but just in case.. parent should be a NavGroup.
15035 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15036 Roo.log(['register', tg, this]);
15039 var i = tg.tabs.length - 1;
15041 if(this.active && tg.bullets > 0 && i < tg.bullets){
15042 tg.setActiveBullet(i);
15049 onRender : function(ct, position)
15051 // Roo.log("Call onRender: " + this.xtype);
15053 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15061 setActive: function(state)
15063 Roo.log("panel - set active " + this.tabId + "=" + state);
15065 this.active = state;
15067 this.el.removeClass('active');
15069 } else if (!this.el.hasClass('active')) {
15070 this.el.addClass('active');
15073 this.fireEvent('changed', this, state);
15090 * @class Roo.bootstrap.DateField
15091 * @extends Roo.bootstrap.Input
15092 * Bootstrap DateField class
15093 * @cfg {Number} weekStart default 0
15094 * @cfg {String} viewMode default empty, (months|years)
15095 * @cfg {String} minViewMode default empty, (months|years)
15096 * @cfg {Number} startDate default -Infinity
15097 * @cfg {Number} endDate default Infinity
15098 * @cfg {Boolean} todayHighlight default false
15099 * @cfg {Boolean} todayBtn default false
15100 * @cfg {Boolean} calendarWeeks default false
15101 * @cfg {Object} daysOfWeekDisabled default empty
15102 * @cfg {Boolean} singleMode default false (true | false)
15104 * @cfg {Boolean} keyboardNavigation default true
15105 * @cfg {String} language default en
15108 * Create a new DateField
15109 * @param {Object} config The config object
15112 Roo.bootstrap.DateField = function(config){
15113 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15117 * Fires when this field show.
15118 * @param {Roo.bootstrap.DateField} this
15119 * @param {Mixed} date The date value
15124 * Fires when this field hide.
15125 * @param {Roo.bootstrap.DateField} this
15126 * @param {Mixed} date The date value
15131 * Fires when select a date.
15132 * @param {Roo.bootstrap.DateField} this
15133 * @param {Mixed} date The date value
15139 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15142 * @cfg {String} format
15143 * The default date format string which can be overriden for localization support. The format must be
15144 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15148 * @cfg {String} altFormats
15149 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15150 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15152 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15160 todayHighlight : false,
15166 keyboardNavigation: true,
15168 calendarWeeks: false,
15170 startDate: -Infinity,
15174 daysOfWeekDisabled: [],
15178 singleMode : false,
15180 UTCDate: function()
15182 return new Date(Date.UTC.apply(Date, arguments));
15185 UTCToday: function()
15187 var today = new Date();
15188 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15191 getDate: function() {
15192 var d = this.getUTCDate();
15193 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15196 getUTCDate: function() {
15200 setDate: function(d) {
15201 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15204 setUTCDate: function(d) {
15206 this.setValue(this.formatDate(this.date));
15209 onRender: function(ct, position)
15212 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15214 this.language = this.language || 'en';
15215 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15216 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15218 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15219 this.format = this.format || 'm/d/y';
15220 this.isInline = false;
15221 this.isInput = true;
15222 this.component = this.el.select('.add-on', true).first() || false;
15223 this.component = (this.component && this.component.length === 0) ? false : this.component;
15224 this.hasInput = this.component && this.inputEL().length;
15226 if (typeof(this.minViewMode === 'string')) {
15227 switch (this.minViewMode) {
15229 this.minViewMode = 1;
15232 this.minViewMode = 2;
15235 this.minViewMode = 0;
15240 if (typeof(this.viewMode === 'string')) {
15241 switch (this.viewMode) {
15254 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15256 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15258 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15260 this.picker().on('mousedown', this.onMousedown, this);
15261 this.picker().on('click', this.onClick, this);
15263 this.picker().addClass('datepicker-dropdown');
15265 this.startViewMode = this.viewMode;
15267 if(this.singleMode){
15268 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15269 v.setVisibilityMode(Roo.Element.DISPLAY)
15273 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15274 v.setStyle('width', '189px');
15278 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15279 if(!this.calendarWeeks){
15284 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15285 v.attr('colspan', function(i, val){
15286 return parseInt(val) + 1;
15291 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15293 this.setStartDate(this.startDate);
15294 this.setEndDate(this.endDate);
15296 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15303 if(this.isInline) {
15308 picker : function()
15310 return this.pickerEl;
15311 // return this.el.select('.datepicker', true).first();
15314 fillDow: function()
15316 var dowCnt = this.weekStart;
15325 if(this.calendarWeeks){
15333 while (dowCnt < this.weekStart + 7) {
15337 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15341 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15344 fillMonths: function()
15347 var months = this.picker().select('>.datepicker-months td', true).first();
15349 months.dom.innerHTML = '';
15355 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15358 months.createChild(month);
15365 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;
15367 if (this.date < this.startDate) {
15368 this.viewDate = new Date(this.startDate);
15369 } else if (this.date > this.endDate) {
15370 this.viewDate = new Date(this.endDate);
15372 this.viewDate = new Date(this.date);
15380 var d = new Date(this.viewDate),
15381 year = d.getUTCFullYear(),
15382 month = d.getUTCMonth(),
15383 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15384 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15385 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15386 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15387 currentDate = this.date && this.date.valueOf(),
15388 today = this.UTCToday();
15390 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15392 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15394 // this.picker.select('>tfoot th.today').
15395 // .text(dates[this.language].today)
15396 // .toggle(this.todayBtn !== false);
15398 this.updateNavArrows();
15401 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15403 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15405 prevMonth.setUTCDate(day);
15407 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15409 var nextMonth = new Date(prevMonth);
15411 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15413 nextMonth = nextMonth.valueOf();
15415 var fillMonths = false;
15417 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15419 while(prevMonth.valueOf() < nextMonth) {
15422 if (prevMonth.getUTCDay() === this.weekStart) {
15424 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15432 if(this.calendarWeeks){
15433 // ISO 8601: First week contains first thursday.
15434 // ISO also states week starts on Monday, but we can be more abstract here.
15436 // Start of current week: based on weekstart/current date
15437 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15438 // Thursday of this week
15439 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15440 // First Thursday of year, year from thursday
15441 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15442 // Calendar week: ms between thursdays, div ms per day, div 7 days
15443 calWeek = (th - yth) / 864e5 / 7 + 1;
15445 fillMonths.cn.push({
15453 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15455 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15458 if (this.todayHighlight &&
15459 prevMonth.getUTCFullYear() == today.getFullYear() &&
15460 prevMonth.getUTCMonth() == today.getMonth() &&
15461 prevMonth.getUTCDate() == today.getDate()) {
15462 clsName += ' today';
15465 if (currentDate && prevMonth.valueOf() === currentDate) {
15466 clsName += ' active';
15469 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15470 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15471 clsName += ' disabled';
15474 fillMonths.cn.push({
15476 cls: 'day ' + clsName,
15477 html: prevMonth.getDate()
15480 prevMonth.setDate(prevMonth.getDate()+1);
15483 var currentYear = this.date && this.date.getUTCFullYear();
15484 var currentMonth = this.date && this.date.getUTCMonth();
15486 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15488 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15489 v.removeClass('active');
15491 if(currentYear === year && k === currentMonth){
15492 v.addClass('active');
15495 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15496 v.addClass('disabled');
15502 year = parseInt(year/10, 10) * 10;
15504 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15506 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15509 for (var i = -1; i < 11; i++) {
15510 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15512 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15520 showMode: function(dir)
15523 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15526 Roo.each(this.picker().select('>div',true).elements, function(v){
15527 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15530 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15535 if(this.isInline) return;
15537 this.picker().removeClass(['bottom', 'top']);
15539 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15541 * place to the top of element!
15545 this.picker().addClass('top');
15546 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15551 this.picker().addClass('bottom');
15553 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15556 parseDate : function(value)
15558 if(!value || value instanceof Date){
15561 var v = Date.parseDate(value, this.format);
15562 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15563 v = Date.parseDate(value, 'Y-m-d');
15565 if(!v && this.altFormats){
15566 if(!this.altFormatsArray){
15567 this.altFormatsArray = this.altFormats.split("|");
15569 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15570 v = Date.parseDate(value, this.altFormatsArray[i]);
15576 formatDate : function(date, fmt)
15578 return (!date || !(date instanceof Date)) ?
15579 date : date.dateFormat(fmt || this.format);
15582 onFocus : function()
15584 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15588 onBlur : function()
15590 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15592 var d = this.inputEl().getValue();
15601 this.picker().show();
15605 this.fireEvent('show', this, this.date);
15610 if(this.isInline) return;
15611 this.picker().hide();
15612 this.viewMode = this.startViewMode;
15615 this.fireEvent('hide', this, this.date);
15619 onMousedown: function(e)
15621 e.stopPropagation();
15622 e.preventDefault();
15627 Roo.bootstrap.DateField.superclass.keyup.call(this);
15631 setValue: function(v)
15634 // v can be a string or a date..
15637 var d = new Date(this.parseDate(v) ).clearTime();
15639 if(isNaN(d.getTime())){
15640 this.date = this.viewDate = '';
15641 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15645 v = this.formatDate(d);
15647 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15649 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15653 this.fireEvent('select', this, this.date);
15657 getValue: function()
15659 return this.formatDate(this.date);
15662 fireKey: function(e)
15664 if (!this.picker().isVisible()){
15665 if (e.keyCode == 27) // allow escape to hide and re-show picker
15670 var dateChanged = false,
15672 newDate, newViewDate;
15677 e.preventDefault();
15681 if (!this.keyboardNavigation) break;
15682 dir = e.keyCode == 37 ? -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);
15693 newViewDate = new Date(this.viewDate);
15694 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
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;
15707 if (!this.keyboardNavigation) break;
15708 dir = e.keyCode == 38 ? -1 : 1;
15710 newDate = this.moveYear(this.date, dir);
15711 newViewDate = this.moveYear(this.viewDate, dir);
15712 } else if (e.shiftKey){
15713 newDate = this.moveMonth(this.date, dir);
15714 newViewDate = this.moveMonth(this.viewDate, dir);
15716 newDate = new Date(this.date);
15717 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15718 newViewDate = new Date(this.viewDate);
15719 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15721 if (this.dateWithinRange(newDate)){
15722 this.date = newDate;
15723 this.viewDate = newViewDate;
15724 this.setValue(this.formatDate(this.date));
15726 e.preventDefault();
15727 dateChanged = true;
15731 this.setValue(this.formatDate(this.date));
15733 e.preventDefault();
15736 this.setValue(this.formatDate(this.date));
15750 onClick: function(e)
15752 e.stopPropagation();
15753 e.preventDefault();
15755 var target = e.getTarget();
15757 if(target.nodeName.toLowerCase() === 'i'){
15758 target = Roo.get(target).dom.parentNode;
15761 var nodeName = target.nodeName;
15762 var className = target.className;
15763 var html = target.innerHTML;
15764 //Roo.log(nodeName);
15766 switch(nodeName.toLowerCase()) {
15768 switch(className) {
15774 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15775 switch(this.viewMode){
15777 this.viewDate = this.moveMonth(this.viewDate, dir);
15781 this.viewDate = this.moveYear(this.viewDate, dir);
15787 var date = new Date();
15788 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15790 this.setValue(this.formatDate(this.date));
15797 if (className.indexOf('disabled') < 0) {
15798 this.viewDate.setUTCDate(1);
15799 if (className.indexOf('month') > -1) {
15800 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15802 var year = parseInt(html, 10) || 0;
15803 this.viewDate.setUTCFullYear(year);
15807 if(this.singleMode){
15808 this.setValue(this.formatDate(this.viewDate));
15819 //Roo.log(className);
15820 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15821 var day = parseInt(html, 10) || 1;
15822 var year = this.viewDate.getUTCFullYear(),
15823 month = this.viewDate.getUTCMonth();
15825 if (className.indexOf('old') > -1) {
15832 } else if (className.indexOf('new') > -1) {
15840 //Roo.log([year,month,day]);
15841 this.date = this.UTCDate(year, month, day,0,0,0,0);
15842 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15844 //Roo.log(this.formatDate(this.date));
15845 this.setValue(this.formatDate(this.date));
15852 setStartDate: function(startDate)
15854 this.startDate = startDate || -Infinity;
15855 if (this.startDate !== -Infinity) {
15856 this.startDate = this.parseDate(this.startDate);
15859 this.updateNavArrows();
15862 setEndDate: function(endDate)
15864 this.endDate = endDate || Infinity;
15865 if (this.endDate !== Infinity) {
15866 this.endDate = this.parseDate(this.endDate);
15869 this.updateNavArrows();
15872 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15874 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15875 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15876 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15878 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15879 return parseInt(d, 10);
15882 this.updateNavArrows();
15885 updateNavArrows: function()
15887 if(this.singleMode){
15891 var d = new Date(this.viewDate),
15892 year = d.getUTCFullYear(),
15893 month = d.getUTCMonth();
15895 Roo.each(this.picker().select('.prev', true).elements, function(v){
15897 switch (this.viewMode) {
15900 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15906 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15913 Roo.each(this.picker().select('.next', true).elements, function(v){
15915 switch (this.viewMode) {
15918 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15924 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15932 moveMonth: function(date, dir)
15934 if (!dir) return date;
15935 var new_date = new Date(date.valueOf()),
15936 day = new_date.getUTCDate(),
15937 month = new_date.getUTCMonth(),
15938 mag = Math.abs(dir),
15940 dir = dir > 0 ? 1 : -1;
15943 // If going back one month, make sure month is not current month
15944 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15946 return new_date.getUTCMonth() == month;
15948 // If going forward one month, make sure month is as expected
15949 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15951 return new_date.getUTCMonth() != new_month;
15953 new_month = month + dir;
15954 new_date.setUTCMonth(new_month);
15955 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15956 if (new_month < 0 || new_month > 11)
15957 new_month = (new_month + 12) % 12;
15959 // For magnitudes >1, move one month at a time...
15960 for (var i=0; i<mag; i++)
15961 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15962 new_date = this.moveMonth(new_date, dir);
15963 // ...then reset the day, keeping it in the new month
15964 new_month = new_date.getUTCMonth();
15965 new_date.setUTCDate(day);
15967 return new_month != new_date.getUTCMonth();
15970 // Common date-resetting loop -- if date is beyond end of month, make it
15973 new_date.setUTCDate(--day);
15974 new_date.setUTCMonth(new_month);
15979 moveYear: function(date, dir)
15981 return this.moveMonth(date, dir*12);
15984 dateWithinRange: function(date)
15986 return date >= this.startDate && date <= this.endDate;
15992 this.picker().remove();
15997 Roo.apply(Roo.bootstrap.DateField, {
16008 html: '<i class="fa fa-arrow-left"/>'
16018 html: '<i class="fa fa-arrow-right"/>'
16060 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16061 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16062 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16063 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16064 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16077 navFnc: 'FullYear',
16082 navFnc: 'FullYear',
16087 Roo.apply(Roo.bootstrap.DateField, {
16091 cls: 'datepicker dropdown-menu roo-dynamic',
16095 cls: 'datepicker-days',
16099 cls: 'table-condensed',
16101 Roo.bootstrap.DateField.head,
16105 Roo.bootstrap.DateField.footer
16112 cls: 'datepicker-months',
16116 cls: 'table-condensed',
16118 Roo.bootstrap.DateField.head,
16119 Roo.bootstrap.DateField.content,
16120 Roo.bootstrap.DateField.footer
16127 cls: 'datepicker-years',
16131 cls: 'table-condensed',
16133 Roo.bootstrap.DateField.head,
16134 Roo.bootstrap.DateField.content,
16135 Roo.bootstrap.DateField.footer
16154 * @class Roo.bootstrap.TimeField
16155 * @extends Roo.bootstrap.Input
16156 * Bootstrap DateField class
16160 * Create a new TimeField
16161 * @param {Object} config The config object
16164 Roo.bootstrap.TimeField = function(config){
16165 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16169 * Fires when this field show.
16170 * @param {Roo.bootstrap.DateField} thisthis
16171 * @param {Mixed} date The date value
16176 * Fires when this field hide.
16177 * @param {Roo.bootstrap.DateField} this
16178 * @param {Mixed} date The date value
16183 * Fires when select a date.
16184 * @param {Roo.bootstrap.DateField} this
16185 * @param {Mixed} date The date value
16191 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16194 * @cfg {String} format
16195 * The default time format string which can be overriden for localization support. The format must be
16196 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16200 onRender: function(ct, position)
16203 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16205 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16207 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16209 this.pop = this.picker().select('>.datepicker-time',true).first();
16210 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16212 this.picker().on('mousedown', this.onMousedown, this);
16213 this.picker().on('click', this.onClick, this);
16215 this.picker().addClass('datepicker-dropdown');
16220 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16221 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16222 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16223 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16224 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16225 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16229 fireKey: function(e){
16230 if (!this.picker().isVisible()){
16231 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16237 e.preventDefault();
16245 this.onTogglePeriod();
16248 this.onIncrementMinutes();
16251 this.onDecrementMinutes();
16260 onClick: function(e) {
16261 e.stopPropagation();
16262 e.preventDefault();
16265 picker : function()
16267 return this.el.select('.datepicker', true).first();
16270 fillTime: function()
16272 var time = this.pop.select('tbody', true).first();
16274 time.dom.innerHTML = '';
16289 cls: 'hours-up glyphicon glyphicon-chevron-up'
16309 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16330 cls: 'timepicker-hour',
16345 cls: 'timepicker-minute',
16360 cls: 'btn btn-primary period',
16382 cls: 'hours-down glyphicon glyphicon-chevron-down'
16402 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16420 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16427 var hours = this.time.getHours();
16428 var minutes = this.time.getMinutes();
16441 hours = hours - 12;
16445 hours = '0' + hours;
16449 minutes = '0' + minutes;
16452 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16453 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16454 this.pop.select('button', true).first().dom.innerHTML = period;
16460 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16462 var cls = ['bottom'];
16464 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16471 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16476 this.picker().addClass(cls.join('-'));
16480 Roo.each(cls, function(c){
16482 _this.picker().setTop(_this.inputEl().getHeight());
16486 _this.picker().setTop(0 - _this.picker().getHeight());
16491 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16495 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16502 onFocus : function()
16504 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16508 onBlur : function()
16510 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16516 this.picker().show();
16521 this.fireEvent('show', this, this.date);
16526 this.picker().hide();
16529 this.fireEvent('hide', this, this.date);
16532 setTime : function()
16535 this.setValue(this.time.format(this.format));
16537 this.fireEvent('select', this, this.date);
16542 onMousedown: function(e){
16543 e.stopPropagation();
16544 e.preventDefault();
16547 onIncrementHours: function()
16549 Roo.log('onIncrementHours');
16550 this.time = this.time.add(Date.HOUR, 1);
16555 onDecrementHours: function()
16557 Roo.log('onDecrementHours');
16558 this.time = this.time.add(Date.HOUR, -1);
16562 onIncrementMinutes: function()
16564 Roo.log('onIncrementMinutes');
16565 this.time = this.time.add(Date.MINUTE, 1);
16569 onDecrementMinutes: function()
16571 Roo.log('onDecrementMinutes');
16572 this.time = this.time.add(Date.MINUTE, -1);
16576 onTogglePeriod: function()
16578 Roo.log('onTogglePeriod');
16579 this.time = this.time.add(Date.HOUR, 12);
16586 Roo.apply(Roo.bootstrap.TimeField, {
16616 cls: 'btn btn-info ok',
16628 Roo.apply(Roo.bootstrap.TimeField, {
16632 cls: 'datepicker dropdown-menu',
16636 cls: 'datepicker-time',
16640 cls: 'table-condensed',
16642 Roo.bootstrap.TimeField.content,
16643 Roo.bootstrap.TimeField.footer
16662 * @class Roo.bootstrap.MonthField
16663 * @extends Roo.bootstrap.Input
16664 * Bootstrap MonthField class
16666 * @cfg {String} language default en
16669 * Create a new MonthField
16670 * @param {Object} config The config object
16673 Roo.bootstrap.MonthField = function(config){
16674 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16679 * Fires when this field show.
16680 * @param {Roo.bootstrap.MonthField} this
16681 * @param {Mixed} date The date value
16686 * Fires when this field hide.
16687 * @param {Roo.bootstrap.MonthField} this
16688 * @param {Mixed} date The date value
16693 * Fires when select a date.
16694 * @param {Roo.bootstrap.MonthField} this
16695 * @param {String} oldvalue The old value
16696 * @param {String} newvalue The new value
16702 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16704 onRender: function(ct, position)
16707 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16709 this.language = this.language || 'en';
16710 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16711 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16713 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16714 this.isInline = false;
16715 this.isInput = true;
16716 this.component = this.el.select('.add-on', true).first() || false;
16717 this.component = (this.component && this.component.length === 0) ? false : this.component;
16718 this.hasInput = this.component && this.inputEL().length;
16720 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16722 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16724 this.picker().on('mousedown', this.onMousedown, this);
16725 this.picker().on('click', this.onClick, this);
16727 this.picker().addClass('datepicker-dropdown');
16729 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16730 v.setStyle('width', '189px');
16737 if(this.isInline) {
16743 setValue: function(v, suppressEvent)
16745 var o = this.getValue();
16747 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16751 if(suppressEvent !== true){
16752 this.fireEvent('select', this, o, v);
16757 getValue: function()
16762 onClick: function(e)
16764 e.stopPropagation();
16765 e.preventDefault();
16767 var target = e.getTarget();
16769 if(target.nodeName.toLowerCase() === 'i'){
16770 target = Roo.get(target).dom.parentNode;
16773 var nodeName = target.nodeName;
16774 var className = target.className;
16775 var html = target.innerHTML;
16777 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16781 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16783 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16789 picker : function()
16791 return this.pickerEl;
16794 fillMonths: function()
16797 var months = this.picker().select('>.datepicker-months td', true).first();
16799 months.dom.innerHTML = '';
16805 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16808 months.createChild(month);
16817 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16818 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16821 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16822 e.removeClass('active');
16824 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16825 e.addClass('active');
16832 if(this.isInline) return;
16834 this.picker().removeClass(['bottom', 'top']);
16836 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16838 * place to the top of element!
16842 this.picker().addClass('top');
16843 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16848 this.picker().addClass('bottom');
16850 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16853 onFocus : function()
16855 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16859 onBlur : function()
16861 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16863 var d = this.inputEl().getValue();
16872 this.picker().show();
16873 this.picker().select('>.datepicker-months', true).first().show();
16877 this.fireEvent('show', this, this.date);
16882 if(this.isInline) return;
16883 this.picker().hide();
16884 this.fireEvent('hide', this, this.date);
16888 onMousedown: function(e)
16890 e.stopPropagation();
16891 e.preventDefault();
16896 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16900 fireKey: function(e)
16902 if (!this.picker().isVisible()){
16903 if (e.keyCode == 27) // allow escape to hide and re-show picker
16913 e.preventDefault();
16917 dir = e.keyCode == 37 ? -1 : 1;
16919 this.vIndex = this.vIndex + dir;
16921 if(this.vIndex < 0){
16925 if(this.vIndex > 11){
16929 if(isNaN(this.vIndex)){
16933 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16939 dir = e.keyCode == 38 ? -1 : 1;
16941 this.vIndex = this.vIndex + dir * 4;
16943 if(this.vIndex < 0){
16947 if(this.vIndex > 11){
16951 if(isNaN(this.vIndex)){
16955 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16960 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16961 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16965 e.preventDefault();
16968 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16969 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16985 this.picker().remove();
16990 Roo.apply(Roo.bootstrap.MonthField, {
17009 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17010 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17015 Roo.apply(Roo.bootstrap.MonthField, {
17019 cls: 'datepicker dropdown-menu roo-dynamic',
17023 cls: 'datepicker-months',
17027 cls: 'table-condensed',
17029 Roo.bootstrap.DateField.content
17049 * @class Roo.bootstrap.CheckBox
17050 * @extends Roo.bootstrap.Input
17051 * Bootstrap CheckBox class
17053 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17054 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17055 * @cfg {String} boxLabel The text that appears beside the checkbox
17056 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17057 * @cfg {Boolean} checked initnal the element
17058 * @cfg {Boolean} inline inline the element (default false)
17059 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17062 * Create a new CheckBox
17063 * @param {Object} config The config object
17066 Roo.bootstrap.CheckBox = function(config){
17067 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17072 * Fires when the element is checked or unchecked.
17073 * @param {Roo.bootstrap.CheckBox} this This input
17074 * @param {Boolean} checked The new checked value
17081 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17083 inputType: 'checkbox',
17091 getAutoCreate : function()
17093 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17099 cfg.cls = 'form-group ' + this.inputType; //input-group
17102 cfg.cls += ' ' + this.inputType + '-inline';
17108 type : this.inputType,
17109 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17110 cls : 'roo-' + this.inputType, //'form-box',
17111 placeholder : this.placeholder || ''
17115 if (this.weight) { // Validity check?
17116 cfg.cls += " " + this.inputType + "-" + this.weight;
17119 if (this.disabled) {
17120 input.disabled=true;
17124 input.checked = this.checked;
17128 input.name = this.name;
17132 input.cls += ' input-' + this.size;
17137 ['xs','sm','md','lg'].map(function(size){
17138 if (settings[size]) {
17139 cfg.cls += ' col-' + size + '-' + settings[size];
17143 var inputblock = input;
17145 if (this.before || this.after) {
17148 cls : 'input-group',
17153 inputblock.cn.push({
17155 cls : 'input-group-addon',
17160 inputblock.cn.push(input);
17163 inputblock.cn.push({
17165 cls : 'input-group-addon',
17172 if (align ==='left' && this.fieldLabel.length) {
17173 Roo.log("left and has label");
17179 cls : 'control-label col-md-' + this.labelWidth,
17180 html : this.fieldLabel
17184 cls : "col-md-" + (12 - this.labelWidth),
17191 } else if ( this.fieldLabel.length) {
17196 tag: this.boxLabel ? 'span' : 'label',
17198 cls: 'control-label box-input-label',
17199 //cls : 'input-group-addon',
17200 html : this.fieldLabel
17210 Roo.log(" no label && no align");
17211 cfg.cn = [ inputblock ] ;
17216 var boxLabelCfg = {
17218 //'for': id, // box label is handled by onclick - so no for...
17220 html: this.boxLabel
17224 boxLabelCfg.tooltip = this.tooltip;
17227 cfg.cn.push(boxLabelCfg);
17237 * return the real input element.
17239 inputEl: function ()
17241 return this.el.select('input.roo-' + this.inputType,true).first();
17244 labelEl: function()
17246 return this.el.select('label.control-label',true).first();
17248 /* depricated... */
17252 return this.labelEl();
17255 initEvents : function()
17257 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17259 this.inputEl().on('click', this.onClick, this);
17261 if (this.boxLabel) {
17262 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17265 this.startValue = this.getValue();
17268 Roo.bootstrap.CheckBox.register(this);
17272 onClick : function()
17274 this.setChecked(!this.checked);
17277 setChecked : function(state,suppressEvent)
17279 this.startValue = this.getValue();
17281 if(this.inputType == 'radio'){
17283 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17284 e.dom.checked = false;
17287 this.inputEl().dom.checked = true;
17289 this.inputEl().dom.value = this.inputValue;
17291 if(suppressEvent !== true){
17292 this.fireEvent('check', this, true);
17300 this.checked = state;
17302 this.inputEl().dom.checked = state;
17304 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17306 if(suppressEvent !== true){
17307 this.fireEvent('check', this, state);
17313 getValue : function()
17315 if(this.inputType == 'radio'){
17316 return this.getGroupValue();
17319 return this.inputEl().getValue();
17323 getGroupValue : function()
17325 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17329 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17332 setValue : function(v,suppressEvent)
17334 if(this.inputType == 'radio'){
17335 this.setGroupValue(v, suppressEvent);
17339 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17344 setGroupValue : function(v, suppressEvent)
17346 this.startValue = this.getValue();
17348 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17349 e.dom.checked = false;
17351 if(e.dom.value == v){
17352 e.dom.checked = true;
17356 if(suppressEvent !== true){
17357 this.fireEvent('check', this, true);
17365 validate : function()
17369 (this.inputType == 'radio' && this.validateRadio()) ||
17370 (this.inputType == 'checkbox' && this.validateCheckbox())
17376 this.markInvalid();
17380 validateRadio : function()
17384 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17385 if(!e.dom.checked){
17397 validateCheckbox : function()
17400 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17403 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17411 for(var i in group){
17416 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17423 * Mark this field as valid
17425 markValid : function()
17427 if(this.allowBlank){
17433 this.fireEvent('valid', this);
17435 if(this.inputType == 'radio'){
17436 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17437 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17438 e.findParent('.form-group', false, true).addClass(_this.validClass);
17445 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17446 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17450 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17456 for(var i in group){
17457 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17458 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17463 * Mark this field as invalid
17464 * @param {String} msg The validation message
17466 markInvalid : function(msg)
17468 if(this.allowBlank){
17474 this.fireEvent('invalid', this, msg);
17476 if(this.inputType == 'radio'){
17477 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17478 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17479 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17486 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17487 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17491 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17497 for(var i in group){
17498 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17499 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17506 Roo.apply(Roo.bootstrap.CheckBox, {
17511 * register a CheckBox Group
17512 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17514 register : function(checkbox)
17516 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17517 this.groups[checkbox.groupId] = {};
17520 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17524 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17528 * fetch a CheckBox Group based on the group ID
17529 * @param {string} the group ID
17530 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17532 get: function(groupId) {
17533 if (typeof(this.groups[groupId]) == 'undefined') {
17537 return this.groups[groupId] ;
17549 *<div class="radio">
17551 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17552 Option one is this and that—be sure to include why it's great
17559 *<label class="radio-inline">fieldLabel</label>
17560 *<label class="radio-inline">
17561 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17569 * @class Roo.bootstrap.Radio
17570 * @extends Roo.bootstrap.CheckBox
17571 * Bootstrap Radio class
17574 * Create a new Radio
17575 * @param {Object} config The config object
17578 Roo.bootstrap.Radio = function(config){
17579 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17583 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17585 inputType: 'radio',
17589 getAutoCreate : function()
17591 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17592 align = align || 'left'; // default...
17599 tag : this.inline ? 'span' : 'div',
17604 var inline = this.inline ? ' radio-inline' : '';
17608 // does not need for, as we wrap the input with it..
17610 cls : 'control-label box-label' + inline,
17613 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17617 //cls : 'control-label' + inline,
17618 html : this.fieldLabel,
17619 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17628 type : this.inputType,
17629 //value : (!this.checked) ? this.valueOff : this.inputValue,
17630 value : this.inputValue,
17632 placeholder : this.placeholder || '' // ?? needed????
17635 if (this.weight) { // Validity check?
17636 input.cls += " radio-" + this.weight;
17638 if (this.disabled) {
17639 input.disabled=true;
17643 input.checked = this.checked;
17647 input.name = this.name;
17651 input.cls += ' input-' + this.size;
17654 //?? can span's inline have a width??
17657 ['xs','sm','md','lg'].map(function(size){
17658 if (settings[size]) {
17659 cfg.cls += ' col-' + size + '-' + settings[size];
17663 var inputblock = input;
17665 if (this.before || this.after) {
17668 cls : 'input-group',
17673 inputblock.cn.push({
17675 cls : 'input-group-addon',
17679 inputblock.cn.push(input);
17681 inputblock.cn.push({
17683 cls : 'input-group-addon',
17691 if (this.fieldLabel && this.fieldLabel.length) {
17692 cfg.cn.push(fieldLabel);
17695 // normal bootstrap puts the input inside the label.
17696 // however with our styled version - it has to go after the input.
17698 //lbl.cn.push(inputblock);
17702 cls: 'radio' + inline,
17709 cfg.cn.push( lblwrap);
17714 html: this.boxLabel
17723 initEvents : function()
17725 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17727 this.inputEl().on('click', this.onClick, this);
17728 if (this.boxLabel) {
17729 Roo.log('find label')
17730 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17735 inputEl: function ()
17737 return this.el.select('input.roo-radio',true).first();
17739 onClick : function()
17742 this.setChecked(true);
17745 setChecked : function(state,suppressEvent)
17748 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17749 v.dom.checked = false;
17752 Roo.log(this.inputEl().dom);
17753 this.checked = state;
17754 this.inputEl().dom.checked = state;
17756 if(suppressEvent !== true){
17757 this.fireEvent('check', this, state);
17760 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17764 getGroupValue : function()
17767 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17768 if(v.dom.checked == true){
17769 value = v.dom.value;
17777 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17778 * @return {Mixed} value The field value
17780 getValue : function(){
17781 return this.getGroupValue();
17787 //<script type="text/javascript">
17790 * Based Ext JS Library 1.1.1
17791 * Copyright(c) 2006-2007, Ext JS, LLC.
17797 * @class Roo.HtmlEditorCore
17798 * @extends Roo.Component
17799 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17801 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17804 Roo.HtmlEditorCore = function(config){
17807 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17812 * @event initialize
17813 * Fires when the editor is fully initialized (including the iframe)
17814 * @param {Roo.HtmlEditorCore} this
17819 * Fires when the editor is first receives the focus. Any insertion must wait
17820 * until after this event.
17821 * @param {Roo.HtmlEditorCore} this
17825 * @event beforesync
17826 * Fires before the textarea is updated with content from the editor iframe. Return false
17827 * to cancel the sync.
17828 * @param {Roo.HtmlEditorCore} this
17829 * @param {String} html
17833 * @event beforepush
17834 * Fires before the iframe editor is updated with content from the textarea. Return false
17835 * to cancel the push.
17836 * @param {Roo.HtmlEditorCore} this
17837 * @param {String} html
17842 * Fires when the textarea is updated with content from the editor iframe.
17843 * @param {Roo.HtmlEditorCore} this
17844 * @param {String} html
17849 * Fires when the iframe editor is updated with content from the textarea.
17850 * @param {Roo.HtmlEditorCore} this
17851 * @param {String} html
17856 * @event editorevent
17857 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17858 * @param {Roo.HtmlEditorCore} this
17864 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17866 // defaults : white / black...
17867 this.applyBlacklists();
17874 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17878 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17884 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17889 * @cfg {Number} height (in pixels)
17893 * @cfg {Number} width (in pixels)
17898 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17901 stylesheets: false,
17906 // private properties
17907 validationEvent : false,
17909 initialized : false,
17911 sourceEditMode : false,
17912 onFocus : Roo.emptyFn,
17914 hideMode:'offsets',
17918 // blacklist + whitelisted elements..
17925 * Protected method that will not generally be called directly. It
17926 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17927 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17929 getDocMarkup : function(){
17933 // inherit styels from page...??
17934 if (this.stylesheets === false) {
17936 Roo.get(document.head).select('style').each(function(node) {
17937 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17940 Roo.get(document.head).select('link').each(function(node) {
17941 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17944 } else if (!this.stylesheets.length) {
17946 st = '<style type="text/css">' +
17947 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17953 st += '<style type="text/css">' +
17954 'IMG { cursor: pointer } ' +
17958 return '<html><head>' + st +
17959 //<style type="text/css">' +
17960 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17962 ' </head><body class="roo-htmleditor-body"></body></html>';
17966 onRender : function(ct, position)
17969 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17970 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17973 this.el.dom.style.border = '0 none';
17974 this.el.dom.setAttribute('tabIndex', -1);
17975 this.el.addClass('x-hidden hide');
17979 if(Roo.isIE){ // fix IE 1px bogus margin
17980 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17984 this.frameId = Roo.id();
17988 var iframe = this.owner.wrap.createChild({
17990 cls: 'form-control', // bootstrap..
17992 name: this.frameId,
17993 frameBorder : 'no',
17994 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17999 this.iframe = iframe.dom;
18001 this.assignDocWin();
18003 this.doc.designMode = 'on';
18006 this.doc.write(this.getDocMarkup());
18010 var task = { // must defer to wait for browser to be ready
18012 //console.log("run task?" + this.doc.readyState);
18013 this.assignDocWin();
18014 if(this.doc.body || this.doc.readyState == 'complete'){
18016 this.doc.designMode="on";
18020 Roo.TaskMgr.stop(task);
18021 this.initEditor.defer(10, this);
18028 Roo.TaskMgr.start(task);
18033 onResize : function(w, h)
18035 Roo.log('resize: ' +w + ',' + h );
18036 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18040 if(typeof w == 'number'){
18042 this.iframe.style.width = w + 'px';
18044 if(typeof h == 'number'){
18046 this.iframe.style.height = h + 'px';
18048 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18055 * Toggles the editor between standard and source edit mode.
18056 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18058 toggleSourceEdit : function(sourceEditMode){
18060 this.sourceEditMode = sourceEditMode === true;
18062 if(this.sourceEditMode){
18064 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18067 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18068 //this.iframe.className = '';
18071 //this.setSize(this.owner.wrap.getSize());
18072 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18079 * Protected method that will not generally be called directly. If you need/want
18080 * custom HTML cleanup, this is the method you should override.
18081 * @param {String} html The HTML to be cleaned
18082 * return {String} The cleaned HTML
18084 cleanHtml : function(html){
18085 html = String(html);
18086 if(html.length > 5){
18087 if(Roo.isSafari){ // strip safari nonsense
18088 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18091 if(html == ' '){
18098 * HTML Editor -> Textarea
18099 * Protected method that will not generally be called directly. Syncs the contents
18100 * of the editor iframe with the textarea.
18102 syncValue : function(){
18103 if(this.initialized){
18104 var bd = (this.doc.body || this.doc.documentElement);
18105 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18106 var html = bd.innerHTML;
18108 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18109 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18111 html = '<div style="'+m[0]+'">' + html + '</div>';
18114 html = this.cleanHtml(html);
18115 // fix up the special chars.. normaly like back quotes in word...
18116 // however we do not want to do this with chinese..
18117 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18118 var cc = b.charCodeAt();
18120 (cc >= 0x4E00 && cc < 0xA000 ) ||
18121 (cc >= 0x3400 && cc < 0x4E00 ) ||
18122 (cc >= 0xf900 && cc < 0xfb00 )
18128 if(this.owner.fireEvent('beforesync', this, html) !== false){
18129 this.el.dom.value = html;
18130 this.owner.fireEvent('sync', this, html);
18136 * Protected method that will not generally be called directly. Pushes the value of the textarea
18137 * into the iframe editor.
18139 pushValue : function(){
18140 if(this.initialized){
18141 var v = this.el.dom.value.trim();
18143 // if(v.length < 1){
18147 if(this.owner.fireEvent('beforepush', this, v) !== false){
18148 var d = (this.doc.body || this.doc.documentElement);
18150 this.cleanUpPaste();
18151 this.el.dom.value = d.innerHTML;
18152 this.owner.fireEvent('push', this, v);
18158 deferFocus : function(){
18159 this.focus.defer(10, this);
18163 focus : function(){
18164 if(this.win && !this.sourceEditMode){
18171 assignDocWin: function()
18173 var iframe = this.iframe;
18176 this.doc = iframe.contentWindow.document;
18177 this.win = iframe.contentWindow;
18179 // if (!Roo.get(this.frameId)) {
18182 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18183 // this.win = Roo.get(this.frameId).dom.contentWindow;
18185 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18189 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18190 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18195 initEditor : function(){
18196 //console.log("INIT EDITOR");
18197 this.assignDocWin();
18201 this.doc.designMode="on";
18203 this.doc.write(this.getDocMarkup());
18206 var dbody = (this.doc.body || this.doc.documentElement);
18207 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18208 // this copies styles from the containing element into thsi one..
18209 // not sure why we need all of this..
18210 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18212 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18213 //ss['background-attachment'] = 'fixed'; // w3c
18214 dbody.bgProperties = 'fixed'; // ie
18215 //Roo.DomHelper.applyStyles(dbody, ss);
18216 Roo.EventManager.on(this.doc, {
18217 //'mousedown': this.onEditorEvent,
18218 'mouseup': this.onEditorEvent,
18219 'dblclick': this.onEditorEvent,
18220 'click': this.onEditorEvent,
18221 'keyup': this.onEditorEvent,
18226 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18228 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18229 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18231 this.initialized = true;
18233 this.owner.fireEvent('initialize', this);
18238 onDestroy : function(){
18244 //for (var i =0; i < this.toolbars.length;i++) {
18245 // // fixme - ask toolbars for heights?
18246 // this.toolbars[i].onDestroy();
18249 //this.wrap.dom.innerHTML = '';
18250 //this.wrap.remove();
18255 onFirstFocus : function(){
18257 this.assignDocWin();
18260 this.activated = true;
18263 if(Roo.isGecko){ // prevent silly gecko errors
18265 var s = this.win.getSelection();
18266 if(!s.focusNode || s.focusNode.nodeType != 3){
18267 var r = s.getRangeAt(0);
18268 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18273 this.execCmd('useCSS', true);
18274 this.execCmd('styleWithCSS', false);
18277 this.owner.fireEvent('activate', this);
18281 adjustFont: function(btn){
18282 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18283 //if(Roo.isSafari){ // safari
18286 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18287 if(Roo.isSafari){ // safari
18288 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18289 v = (v < 10) ? 10 : v;
18290 v = (v > 48) ? 48 : v;
18291 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18296 v = Math.max(1, v+adjust);
18298 this.execCmd('FontSize', v );
18301 onEditorEvent : function(e){
18302 this.owner.fireEvent('editorevent', this, e);
18303 // this.updateToolbar();
18304 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18307 insertTag : function(tg)
18309 // could be a bit smarter... -> wrap the current selected tRoo..
18310 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18312 range = this.createRange(this.getSelection());
18313 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18314 wrappingNode.appendChild(range.extractContents());
18315 range.insertNode(wrappingNode);
18322 this.execCmd("formatblock", tg);
18326 insertText : function(txt)
18330 var range = this.createRange();
18331 range.deleteContents();
18332 //alert(Sender.getAttribute('label'));
18334 range.insertNode(this.doc.createTextNode(txt));
18340 * Executes a Midas editor command on the editor document and performs necessary focus and
18341 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18342 * @param {String} cmd The Midas command
18343 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18345 relayCmd : function(cmd, value){
18347 this.execCmd(cmd, value);
18348 this.owner.fireEvent('editorevent', this);
18349 //this.updateToolbar();
18350 this.owner.deferFocus();
18354 * Executes a Midas editor command directly on the editor document.
18355 * For visual commands, you should use {@link #relayCmd} instead.
18356 * <b>This should only be called after the editor is initialized.</b>
18357 * @param {String} cmd The Midas command
18358 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18360 execCmd : function(cmd, value){
18361 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18368 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18370 * @param {String} text | dom node..
18372 insertAtCursor : function(text)
18377 if(!this.activated){
18383 var r = this.doc.selection.createRange();
18394 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18398 // from jquery ui (MIT licenced)
18400 var win = this.win;
18402 if (win.getSelection && win.getSelection().getRangeAt) {
18403 range = win.getSelection().getRangeAt(0);
18404 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18405 range.insertNode(node);
18406 } else if (win.document.selection && win.document.selection.createRange) {
18407 // no firefox support
18408 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18409 win.document.selection.createRange().pasteHTML(txt);
18411 // no firefox support
18412 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18413 this.execCmd('InsertHTML', txt);
18422 mozKeyPress : function(e){
18424 var c = e.getCharCode(), cmd;
18427 c = String.fromCharCode(c).toLowerCase();
18441 this.cleanUpPaste.defer(100, this);
18449 e.preventDefault();
18457 fixKeys : function(){ // load time branching for fastest keydown performance
18459 return function(e){
18460 var k = e.getKey(), r;
18463 r = this.doc.selection.createRange();
18466 r.pasteHTML('    ');
18473 r = this.doc.selection.createRange();
18475 var target = r.parentElement();
18476 if(!target || target.tagName.toLowerCase() != 'li'){
18478 r.pasteHTML('<br />');
18484 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18485 this.cleanUpPaste.defer(100, this);
18491 }else if(Roo.isOpera){
18492 return function(e){
18493 var k = e.getKey();
18497 this.execCmd('InsertHTML','    ');
18500 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18501 this.cleanUpPaste.defer(100, this);
18506 }else if(Roo.isSafari){
18507 return function(e){
18508 var k = e.getKey();
18512 this.execCmd('InsertText','\t');
18516 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18517 this.cleanUpPaste.defer(100, this);
18525 getAllAncestors: function()
18527 var p = this.getSelectedNode();
18530 a.push(p); // push blank onto stack..
18531 p = this.getParentElement();
18535 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18539 a.push(this.doc.body);
18543 lastSelNode : false,
18546 getSelection : function()
18548 this.assignDocWin();
18549 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18552 getSelectedNode: function()
18554 // this may only work on Gecko!!!
18556 // should we cache this!!!!
18561 var range = this.createRange(this.getSelection()).cloneRange();
18564 var parent = range.parentElement();
18566 var testRange = range.duplicate();
18567 testRange.moveToElementText(parent);
18568 if (testRange.inRange(range)) {
18571 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18574 parent = parent.parentElement;
18579 // is ancestor a text element.
18580 var ac = range.commonAncestorContainer;
18581 if (ac.nodeType == 3) {
18582 ac = ac.parentNode;
18585 var ar = ac.childNodes;
18588 var other_nodes = [];
18589 var has_other_nodes = false;
18590 for (var i=0;i<ar.length;i++) {
18591 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18594 // fullly contained node.
18596 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18601 // probably selected..
18602 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18603 other_nodes.push(ar[i]);
18607 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18612 has_other_nodes = true;
18614 if (!nodes.length && other_nodes.length) {
18615 nodes= other_nodes;
18617 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18623 createRange: function(sel)
18625 // this has strange effects when using with
18626 // top toolbar - not sure if it's a great idea.
18627 //this.editor.contentWindow.focus();
18628 if (typeof sel != "undefined") {
18630 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18632 return this.doc.createRange();
18635 return this.doc.createRange();
18638 getParentElement: function()
18641 this.assignDocWin();
18642 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18644 var range = this.createRange(sel);
18647 var p = range.commonAncestorContainer;
18648 while (p.nodeType == 3) { // text node
18659 * Range intersection.. the hard stuff...
18663 * [ -- selected range --- ]
18667 * if end is before start or hits it. fail.
18668 * if start is after end or hits it fail.
18670 * if either hits (but other is outside. - then it's not
18676 // @see http://www.thismuchiknow.co.uk/?p=64.
18677 rangeIntersectsNode : function(range, node)
18679 var nodeRange = node.ownerDocument.createRange();
18681 nodeRange.selectNode(node);
18683 nodeRange.selectNodeContents(node);
18686 var rangeStartRange = range.cloneRange();
18687 rangeStartRange.collapse(true);
18689 var rangeEndRange = range.cloneRange();
18690 rangeEndRange.collapse(false);
18692 var nodeStartRange = nodeRange.cloneRange();
18693 nodeStartRange.collapse(true);
18695 var nodeEndRange = nodeRange.cloneRange();
18696 nodeEndRange.collapse(false);
18698 return rangeStartRange.compareBoundaryPoints(
18699 Range.START_TO_START, nodeEndRange) == -1 &&
18700 rangeEndRange.compareBoundaryPoints(
18701 Range.START_TO_START, nodeStartRange) == 1;
18705 rangeCompareNode : function(range, node)
18707 var nodeRange = node.ownerDocument.createRange();
18709 nodeRange.selectNode(node);
18711 nodeRange.selectNodeContents(node);
18715 range.collapse(true);
18717 nodeRange.collapse(true);
18719 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18720 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18722 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18724 var nodeIsBefore = ss == 1;
18725 var nodeIsAfter = ee == -1;
18727 if (nodeIsBefore && nodeIsAfter)
18729 if (!nodeIsBefore && nodeIsAfter)
18730 return 1; //right trailed.
18732 if (nodeIsBefore && !nodeIsAfter)
18733 return 2; // left trailed.
18738 // private? - in a new class?
18739 cleanUpPaste : function()
18741 // cleans up the whole document..
18742 Roo.log('cleanuppaste');
18744 this.cleanUpChildren(this.doc.body);
18745 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18746 if (clean != this.doc.body.innerHTML) {
18747 this.doc.body.innerHTML = clean;
18752 cleanWordChars : function(input) {// change the chars to hex code
18753 var he = Roo.HtmlEditorCore;
18755 var output = input;
18756 Roo.each(he.swapCodes, function(sw) {
18757 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18759 output = output.replace(swapper, sw[1]);
18766 cleanUpChildren : function (n)
18768 if (!n.childNodes.length) {
18771 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18772 this.cleanUpChild(n.childNodes[i]);
18779 cleanUpChild : function (node)
18782 //console.log(node);
18783 if (node.nodeName == "#text") {
18784 // clean up silly Windows -- stuff?
18787 if (node.nodeName == "#comment") {
18788 node.parentNode.removeChild(node);
18789 // clean up silly Windows -- stuff?
18792 var lcname = node.tagName.toLowerCase();
18793 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18794 // whitelist of tags..
18796 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18798 node.parentNode.removeChild(node);
18803 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18805 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18806 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18808 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18809 // remove_keep_children = true;
18812 if (remove_keep_children) {
18813 this.cleanUpChildren(node);
18814 // inserts everything just before this node...
18815 while (node.childNodes.length) {
18816 var cn = node.childNodes[0];
18817 node.removeChild(cn);
18818 node.parentNode.insertBefore(cn, node);
18820 node.parentNode.removeChild(node);
18824 if (!node.attributes || !node.attributes.length) {
18825 this.cleanUpChildren(node);
18829 function cleanAttr(n,v)
18832 if (v.match(/^\./) || v.match(/^\//)) {
18835 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18838 if (v.match(/^#/)) {
18841 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18842 node.removeAttribute(n);
18846 var cwhite = this.cwhite;
18847 var cblack = this.cblack;
18849 function cleanStyle(n,v)
18851 if (v.match(/expression/)) { //XSS?? should we even bother..
18852 node.removeAttribute(n);
18856 var parts = v.split(/;/);
18859 Roo.each(parts, function(p) {
18860 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18864 var l = p.split(':').shift().replace(/\s+/g,'');
18865 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18867 if ( cwhite.length && cblack.indexOf(l) > -1) {
18868 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18869 //node.removeAttribute(n);
18873 // only allow 'c whitelisted system attributes'
18874 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18875 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18876 //node.removeAttribute(n);
18886 if (clean.length) {
18887 node.setAttribute(n, clean.join(';'));
18889 node.removeAttribute(n);
18895 for (var i = node.attributes.length-1; i > -1 ; i--) {
18896 var a = node.attributes[i];
18899 if (a.name.toLowerCase().substr(0,2)=='on') {
18900 node.removeAttribute(a.name);
18903 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18904 node.removeAttribute(a.name);
18907 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18908 cleanAttr(a.name,a.value); // fixme..
18911 if (a.name == 'style') {
18912 cleanStyle(a.name,a.value);
18915 /// clean up MS crap..
18916 // tecnically this should be a list of valid class'es..
18919 if (a.name == 'class') {
18920 if (a.value.match(/^Mso/)) {
18921 node.className = '';
18924 if (a.value.match(/body/)) {
18925 node.className = '';
18936 this.cleanUpChildren(node);
18941 * Clean up MS wordisms...
18943 cleanWord : function(node)
18946 var cleanWordChildren = function()
18948 if (!node.childNodes.length) {
18951 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18952 _t.cleanWord(node.childNodes[i]);
18958 this.cleanWord(this.doc.body);
18961 if (node.nodeName == "#text") {
18962 // clean up silly Windows -- stuff?
18965 if (node.nodeName == "#comment") {
18966 node.parentNode.removeChild(node);
18967 // clean up silly Windows -- stuff?
18971 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18972 node.parentNode.removeChild(node);
18976 // remove - but keep children..
18977 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18978 while (node.childNodes.length) {
18979 var cn = node.childNodes[0];
18980 node.removeChild(cn);
18981 node.parentNode.insertBefore(cn, node);
18983 node.parentNode.removeChild(node);
18984 cleanWordChildren();
18988 if (node.className.length) {
18990 var cn = node.className.split(/\W+/);
18992 Roo.each(cn, function(cls) {
18993 if (cls.match(/Mso[a-zA-Z]+/)) {
18998 node.className = cna.length ? cna.join(' ') : '';
19000 node.removeAttribute("class");
19004 if (node.hasAttribute("lang")) {
19005 node.removeAttribute("lang");
19008 if (node.hasAttribute("style")) {
19010 var styles = node.getAttribute("style").split(";");
19012 Roo.each(styles, function(s) {
19013 if (!s.match(/:/)) {
19016 var kv = s.split(":");
19017 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19020 // what ever is left... we allow.
19023 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19024 if (!nstyle.length) {
19025 node.removeAttribute('style');
19029 cleanWordChildren();
19033 domToHTML : function(currentElement, depth, nopadtext) {
19035 depth = depth || 0;
19036 nopadtext = nopadtext || false;
19038 if (!currentElement) {
19039 return this.domToHTML(this.doc.body);
19042 //Roo.log(currentElement);
19044 var allText = false;
19045 var nodeName = currentElement.nodeName;
19046 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19048 if (nodeName == '#text') {
19050 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19055 if (nodeName != 'BODY') {
19058 // Prints the node tagName, such as <A>, <IMG>, etc
19061 for(i = 0; i < currentElement.attributes.length;i++) {
19063 var aname = currentElement.attributes.item(i).name;
19064 if (!currentElement.attributes.item(i).value.length) {
19067 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19070 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19079 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19082 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19087 // Traverse the tree
19089 var currentElementChild = currentElement.childNodes.item(i);
19090 var allText = true;
19091 var innerHTML = '';
19093 while (currentElementChild) {
19094 // Formatting code (indent the tree so it looks nice on the screen)
19095 var nopad = nopadtext;
19096 if (lastnode == 'SPAN') {
19100 if (currentElementChild.nodeName == '#text') {
19101 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19102 toadd = nopadtext ? toadd : toadd.trim();
19103 if (!nopad && toadd.length > 80) {
19104 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19106 innerHTML += toadd;
19109 currentElementChild = currentElement.childNodes.item(i);
19115 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19117 // Recursively traverse the tree structure of the child node
19118 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19119 lastnode = currentElementChild.nodeName;
19121 currentElementChild=currentElement.childNodes.item(i);
19127 // The remaining code is mostly for formatting the tree
19128 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19133 ret+= "</"+tagName+">";
19139 applyBlacklists : function()
19141 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19142 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19146 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19147 if (b.indexOf(tag) > -1) {
19150 this.white.push(tag);
19154 Roo.each(w, function(tag) {
19155 if (b.indexOf(tag) > -1) {
19158 if (this.white.indexOf(tag) > -1) {
19161 this.white.push(tag);
19166 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19167 if (w.indexOf(tag) > -1) {
19170 this.black.push(tag);
19174 Roo.each(b, function(tag) {
19175 if (w.indexOf(tag) > -1) {
19178 if (this.black.indexOf(tag) > -1) {
19181 this.black.push(tag);
19186 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19187 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19191 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19192 if (b.indexOf(tag) > -1) {
19195 this.cwhite.push(tag);
19199 Roo.each(w, function(tag) {
19200 if (b.indexOf(tag) > -1) {
19203 if (this.cwhite.indexOf(tag) > -1) {
19206 this.cwhite.push(tag);
19211 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19212 if (w.indexOf(tag) > -1) {
19215 this.cblack.push(tag);
19219 Roo.each(b, function(tag) {
19220 if (w.indexOf(tag) > -1) {
19223 if (this.cblack.indexOf(tag) > -1) {
19226 this.cblack.push(tag);
19231 setStylesheets : function(stylesheets)
19233 if(typeof(stylesheets) == 'string'){
19234 Roo.get(this.iframe.contentDocument.head).createChild({
19236 rel : 'stylesheet',
19245 Roo.each(stylesheets, function(s) {
19250 Roo.get(_this.iframe.contentDocument.head).createChild({
19252 rel : 'stylesheet',
19261 removeStylesheets : function()
19265 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19270 // hide stuff that is not compatible
19284 * @event specialkey
19288 * @cfg {String} fieldClass @hide
19291 * @cfg {String} focusClass @hide
19294 * @cfg {String} autoCreate @hide
19297 * @cfg {String} inputType @hide
19300 * @cfg {String} invalidClass @hide
19303 * @cfg {String} invalidText @hide
19306 * @cfg {String} msgFx @hide
19309 * @cfg {String} validateOnBlur @hide
19313 Roo.HtmlEditorCore.white = [
19314 'area', 'br', 'img', 'input', 'hr', 'wbr',
19316 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19317 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19318 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19319 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19320 'table', 'ul', 'xmp',
19322 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19325 'dir', 'menu', 'ol', 'ul', 'dl',
19331 Roo.HtmlEditorCore.black = [
19332 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19334 'base', 'basefont', 'bgsound', 'blink', 'body',
19335 'frame', 'frameset', 'head', 'html', 'ilayer',
19336 'iframe', 'layer', 'link', 'meta', 'object',
19337 'script', 'style' ,'title', 'xml' // clean later..
19339 Roo.HtmlEditorCore.clean = [
19340 'script', 'style', 'title', 'xml'
19342 Roo.HtmlEditorCore.remove = [
19347 Roo.HtmlEditorCore.ablack = [
19351 Roo.HtmlEditorCore.aclean = [
19352 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19356 Roo.HtmlEditorCore.pwhite= [
19357 'http', 'https', 'mailto'
19360 // white listed style attributes.
19361 Roo.HtmlEditorCore.cwhite= [
19362 // 'text-align', /// default is to allow most things..
19368 // black listed style attributes.
19369 Roo.HtmlEditorCore.cblack= [
19370 // 'font-size' -- this can be set by the project
19374 Roo.HtmlEditorCore.swapCodes =[
19393 * @class Roo.bootstrap.HtmlEditor
19394 * @extends Roo.bootstrap.TextArea
19395 * Bootstrap HtmlEditor class
19398 * Create a new HtmlEditor
19399 * @param {Object} config The config object
19402 Roo.bootstrap.HtmlEditor = function(config){
19403 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19404 if (!this.toolbars) {
19405 this.toolbars = [];
19407 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19410 * @event initialize
19411 * Fires when the editor is fully initialized (including the iframe)
19412 * @param {HtmlEditor} this
19417 * Fires when the editor is first receives the focus. Any insertion must wait
19418 * until after this event.
19419 * @param {HtmlEditor} this
19423 * @event beforesync
19424 * Fires before the textarea is updated with content from the editor iframe. Return false
19425 * to cancel the sync.
19426 * @param {HtmlEditor} this
19427 * @param {String} html
19431 * @event beforepush
19432 * Fires before the iframe editor is updated with content from the textarea. Return false
19433 * to cancel the push.
19434 * @param {HtmlEditor} this
19435 * @param {String} html
19440 * Fires when the textarea is updated with content from the editor iframe.
19441 * @param {HtmlEditor} this
19442 * @param {String} html
19447 * Fires when the iframe editor is updated with content from the textarea.
19448 * @param {HtmlEditor} this
19449 * @param {String} html
19453 * @event editmodechange
19454 * Fires when the editor switches edit modes
19455 * @param {HtmlEditor} this
19456 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19458 editmodechange: true,
19460 * @event editorevent
19461 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19462 * @param {HtmlEditor} this
19466 * @event firstfocus
19467 * Fires when on first focus - needed by toolbars..
19468 * @param {HtmlEditor} this
19473 * Auto save the htmlEditor value as a file into Events
19474 * @param {HtmlEditor} this
19478 * @event savedpreview
19479 * preview the saved version of htmlEditor
19480 * @param {HtmlEditor} this
19487 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19491 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19496 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19501 * @cfg {Number} height (in pixels)
19505 * @cfg {Number} width (in pixels)
19510 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19513 stylesheets: false,
19518 // private properties
19519 validationEvent : false,
19521 initialized : false,
19524 onFocus : Roo.emptyFn,
19526 hideMode:'offsets',
19529 tbContainer : false,
19531 toolbarContainer :function() {
19532 return this.wrap.select('.x-html-editor-tb',true).first();
19536 * Protected method that will not generally be called directly. It
19537 * is called when the editor creates its toolbar. Override this method if you need to
19538 * add custom toolbar buttons.
19539 * @param {HtmlEditor} editor
19541 createToolbar : function(){
19543 Roo.log("create toolbars");
19545 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19546 this.toolbars[0].render(this.toolbarContainer());
19550 // if (!editor.toolbars || !editor.toolbars.length) {
19551 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19554 // for (var i =0 ; i < editor.toolbars.length;i++) {
19555 // editor.toolbars[i] = Roo.factory(
19556 // typeof(editor.toolbars[i]) == 'string' ?
19557 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19558 // Roo.bootstrap.HtmlEditor);
19559 // editor.toolbars[i].init(editor);
19565 onRender : function(ct, position)
19567 // Roo.log("Call onRender: " + this.xtype);
19569 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19571 this.wrap = this.inputEl().wrap({
19572 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19575 this.editorcore.onRender(ct, position);
19577 if (this.resizable) {
19578 this.resizeEl = new Roo.Resizable(this.wrap, {
19582 minHeight : this.height,
19583 height: this.height,
19584 handles : this.resizable,
19587 resize : function(r, w, h) {
19588 _t.onResize(w,h); // -something
19594 this.createToolbar(this);
19597 if(!this.width && this.resizable){
19598 this.setSize(this.wrap.getSize());
19600 if (this.resizeEl) {
19601 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19602 // should trigger onReize..
19608 onResize : function(w, h)
19610 Roo.log('resize: ' +w + ',' + h );
19611 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19615 if(this.inputEl() ){
19616 if(typeof w == 'number'){
19617 var aw = w - this.wrap.getFrameWidth('lr');
19618 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19621 if(typeof h == 'number'){
19622 var tbh = -11; // fixme it needs to tool bar size!
19623 for (var i =0; i < this.toolbars.length;i++) {
19624 // fixme - ask toolbars for heights?
19625 tbh += this.toolbars[i].el.getHeight();
19626 //if (this.toolbars[i].footer) {
19627 // tbh += this.toolbars[i].footer.el.getHeight();
19635 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19636 ah -= 5; // knock a few pixes off for look..
19637 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19641 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19642 this.editorcore.onResize(ew,eh);
19647 * Toggles the editor between standard and source edit mode.
19648 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19650 toggleSourceEdit : function(sourceEditMode)
19652 this.editorcore.toggleSourceEdit(sourceEditMode);
19654 if(this.editorcore.sourceEditMode){
19655 Roo.log('editor - showing textarea');
19658 // Roo.log(this.syncValue());
19660 this.inputEl().removeClass(['hide', 'x-hidden']);
19661 this.inputEl().dom.removeAttribute('tabIndex');
19662 this.inputEl().focus();
19664 Roo.log('editor - hiding textarea');
19666 // Roo.log(this.pushValue());
19669 this.inputEl().addClass(['hide', 'x-hidden']);
19670 this.inputEl().dom.setAttribute('tabIndex', -1);
19671 //this.deferFocus();
19674 if(this.resizable){
19675 this.setSize(this.wrap.getSize());
19678 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19681 // private (for BoxComponent)
19682 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19684 // private (for BoxComponent)
19685 getResizeEl : function(){
19689 // private (for BoxComponent)
19690 getPositionEl : function(){
19695 initEvents : function(){
19696 this.originalValue = this.getValue();
19700 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19703 // markInvalid : Roo.emptyFn,
19705 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19708 // clearInvalid : Roo.emptyFn,
19710 setValue : function(v){
19711 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19712 this.editorcore.pushValue();
19717 deferFocus : function(){
19718 this.focus.defer(10, this);
19722 focus : function(){
19723 this.editorcore.focus();
19729 onDestroy : function(){
19735 for (var i =0; i < this.toolbars.length;i++) {
19736 // fixme - ask toolbars for heights?
19737 this.toolbars[i].onDestroy();
19740 this.wrap.dom.innerHTML = '';
19741 this.wrap.remove();
19746 onFirstFocus : function(){
19747 //Roo.log("onFirstFocus");
19748 this.editorcore.onFirstFocus();
19749 for (var i =0; i < this.toolbars.length;i++) {
19750 this.toolbars[i].onFirstFocus();
19756 syncValue : function()
19758 this.editorcore.syncValue();
19761 pushValue : function()
19763 this.editorcore.pushValue();
19767 // hide stuff that is not compatible
19781 * @event specialkey
19785 * @cfg {String} fieldClass @hide
19788 * @cfg {String} focusClass @hide
19791 * @cfg {String} autoCreate @hide
19794 * @cfg {String} inputType @hide
19797 * @cfg {String} invalidClass @hide
19800 * @cfg {String} invalidText @hide
19803 * @cfg {String} msgFx @hide
19806 * @cfg {String} validateOnBlur @hide
19815 Roo.namespace('Roo.bootstrap.htmleditor');
19817 * @class Roo.bootstrap.HtmlEditorToolbar1
19822 new Roo.bootstrap.HtmlEditor({
19825 new Roo.bootstrap.HtmlEditorToolbar1({
19826 disable : { fonts: 1 , format: 1, ..., ... , ...],
19832 * @cfg {Object} disable List of elements to disable..
19833 * @cfg {Array} btns List of additional buttons.
19837 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19840 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19843 Roo.apply(this, config);
19845 // default disabled, based on 'good practice'..
19846 this.disable = this.disable || {};
19847 Roo.applyIf(this.disable, {
19850 specialElements : true
19852 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19854 this.editor = config.editor;
19855 this.editorcore = config.editor.editorcore;
19857 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19859 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19860 // dont call parent... till later.
19862 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19867 editorcore : false,
19872 "h1","h2","h3","h4","h5","h6",
19874 "abbr", "acronym", "address", "cite", "samp", "var",
19878 onRender : function(ct, position)
19880 // Roo.log("Call onRender: " + this.xtype);
19882 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19884 this.el.dom.style.marginBottom = '0';
19886 var editorcore = this.editorcore;
19887 var editor= this.editor;
19890 var btn = function(id,cmd , toggle, handler){
19892 var event = toggle ? 'toggle' : 'click';
19897 xns: Roo.bootstrap,
19900 enableToggle:toggle !== false,
19902 pressed : toggle ? false : null,
19905 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19906 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19915 xns: Roo.bootstrap,
19916 glyphicon : 'font',
19920 xns: Roo.bootstrap,
19924 Roo.each(this.formats, function(f) {
19925 style.menu.items.push({
19927 xns: Roo.bootstrap,
19928 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19933 editorcore.insertTag(this.tagname);
19940 children.push(style);
19943 btn('bold',false,true);
19944 btn('italic',false,true);
19945 btn('align-left', 'justifyleft',true);
19946 btn('align-center', 'justifycenter',true);
19947 btn('align-right' , 'justifyright',true);
19948 btn('link', false, false, function(btn) {
19949 //Roo.log("create link?");
19950 var url = prompt(this.createLinkText, this.defaultLinkValue);
19951 if(url && url != 'http:/'+'/'){
19952 this.editorcore.relayCmd('createlink', url);
19955 btn('list','insertunorderedlist',true);
19956 btn('pencil', false,true, function(btn){
19959 this.toggleSourceEdit(btn.pressed);
19965 xns: Roo.bootstrap,
19970 xns: Roo.bootstrap,
19975 cog.menu.items.push({
19977 xns: Roo.bootstrap,
19978 html : Clean styles,
19983 editorcore.insertTag(this.tagname);
19992 this.xtype = 'NavSimplebar';
19994 for(var i=0;i< children.length;i++) {
19996 this.buttons.add(this.addxtypeChild(children[i]));
20000 editor.on('editorevent', this.updateToolbar, this);
20002 onBtnClick : function(id)
20004 this.editorcore.relayCmd(id);
20005 this.editorcore.focus();
20009 * Protected method that will not generally be called directly. It triggers
20010 * a toolbar update by reading the markup state of the current selection in the editor.
20012 updateToolbar: function(){
20014 if(!this.editorcore.activated){
20015 this.editor.onFirstFocus(); // is this neeed?
20019 var btns = this.buttons;
20020 var doc = this.editorcore.doc;
20021 btns.get('bold').setActive(doc.queryCommandState('bold'));
20022 btns.get('italic').setActive(doc.queryCommandState('italic'));
20023 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20025 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20026 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20027 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20029 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20030 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20033 var ans = this.editorcore.getAllAncestors();
20034 if (this.formatCombo) {
20037 var store = this.formatCombo.store;
20038 this.formatCombo.setValue("");
20039 for (var i =0; i < ans.length;i++) {
20040 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20042 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20050 // hides menus... - so this cant be on a menu...
20051 Roo.bootstrap.MenuMgr.hideAll();
20053 Roo.bootstrap.MenuMgr.hideAll();
20054 //this.editorsyncValue();
20056 onFirstFocus: function() {
20057 this.buttons.each(function(item){
20061 toggleSourceEdit : function(sourceEditMode){
20064 if(sourceEditMode){
20065 Roo.log("disabling buttons");
20066 this.buttons.each( function(item){
20067 if(item.cmd != 'pencil'){
20073 Roo.log("enabling buttons");
20074 if(this.editorcore.initialized){
20075 this.buttons.each( function(item){
20081 Roo.log("calling toggole on editor");
20082 // tell the editor that it's been pressed..
20083 this.editor.toggleSourceEdit(sourceEditMode);
20093 * @class Roo.bootstrap.Table.AbstractSelectionModel
20094 * @extends Roo.util.Observable
20095 * Abstract base class for grid SelectionModels. It provides the interface that should be
20096 * implemented by descendant classes. This class should not be directly instantiated.
20099 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20100 this.locked = false;
20101 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20105 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20106 /** @ignore Called by the grid automatically. Do not call directly. */
20107 init : function(grid){
20113 * Locks the selections.
20116 this.locked = true;
20120 * Unlocks the selections.
20122 unlock : function(){
20123 this.locked = false;
20127 * Returns true if the selections are locked.
20128 * @return {Boolean}
20130 isLocked : function(){
20131 return this.locked;
20135 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20136 * @class Roo.bootstrap.Table.RowSelectionModel
20137 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20138 * It supports multiple selections and keyboard selection/navigation.
20140 * @param {Object} config
20143 Roo.bootstrap.Table.RowSelectionModel = function(config){
20144 Roo.apply(this, config);
20145 this.selections = new Roo.util.MixedCollection(false, function(o){
20150 this.lastActive = false;
20154 * @event selectionchange
20155 * Fires when the selection changes
20156 * @param {SelectionModel} this
20158 "selectionchange" : true,
20160 * @event afterselectionchange
20161 * Fires after the selection changes (eg. by key press or clicking)
20162 * @param {SelectionModel} this
20164 "afterselectionchange" : true,
20166 * @event beforerowselect
20167 * Fires when a row is selected being selected, return false to cancel.
20168 * @param {SelectionModel} this
20169 * @param {Number} rowIndex The selected index
20170 * @param {Boolean} keepExisting False if other selections will be cleared
20172 "beforerowselect" : true,
20175 * Fires when a row is selected.
20176 * @param {SelectionModel} this
20177 * @param {Number} rowIndex The selected index
20178 * @param {Roo.data.Record} r The record
20180 "rowselect" : true,
20182 * @event rowdeselect
20183 * Fires when a row is deselected.
20184 * @param {SelectionModel} this
20185 * @param {Number} rowIndex The selected index
20187 "rowdeselect" : true
20189 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20190 this.locked = false;
20193 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20195 * @cfg {Boolean} singleSelect
20196 * True to allow selection of only one row at a time (defaults to false)
20198 singleSelect : false,
20201 initEvents : function(){
20203 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20204 this.grid.on("mousedown", this.handleMouseDown, this);
20205 }else{ // allow click to work like normal
20206 this.grid.on("rowclick", this.handleDragableRowClick, this);
20209 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20210 "up" : function(e){
20212 this.selectPrevious(e.shiftKey);
20213 }else if(this.last !== false && this.lastActive !== false){
20214 var last = this.last;
20215 this.selectRange(this.last, this.lastActive-1);
20216 this.grid.getView().focusRow(this.lastActive);
20217 if(last !== false){
20221 this.selectFirstRow();
20223 this.fireEvent("afterselectionchange", this);
20225 "down" : function(e){
20227 this.selectNext(e.shiftKey);
20228 }else if(this.last !== false && this.lastActive !== false){
20229 var last = this.last;
20230 this.selectRange(this.last, this.lastActive+1);
20231 this.grid.getView().focusRow(this.lastActive);
20232 if(last !== false){
20236 this.selectFirstRow();
20238 this.fireEvent("afterselectionchange", this);
20243 var view = this.grid.view;
20244 view.on("refresh", this.onRefresh, this);
20245 view.on("rowupdated", this.onRowUpdated, this);
20246 view.on("rowremoved", this.onRemove, this);
20250 onRefresh : function(){
20251 var ds = this.grid.dataSource, i, v = this.grid.view;
20252 var s = this.selections;
20253 s.each(function(r){
20254 if((i = ds.indexOfId(r.id)) != -1){
20263 onRemove : function(v, index, r){
20264 this.selections.remove(r);
20268 onRowUpdated : function(v, index, r){
20269 if(this.isSelected(r)){
20270 v.onRowSelect(index);
20276 * @param {Array} records The records to select
20277 * @param {Boolean} keepExisting (optional) True to keep existing selections
20279 selectRecords : function(records, keepExisting){
20281 this.clearSelections();
20283 var ds = this.grid.dataSource;
20284 for(var i = 0, len = records.length; i < len; i++){
20285 this.selectRow(ds.indexOf(records[i]), true);
20290 * Gets the number of selected rows.
20293 getCount : function(){
20294 return this.selections.length;
20298 * Selects the first row in the grid.
20300 selectFirstRow : function(){
20305 * Select the last row.
20306 * @param {Boolean} keepExisting (optional) True to keep existing selections
20308 selectLastRow : function(keepExisting){
20309 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20313 * Selects the row immediately following the last selected row.
20314 * @param {Boolean} keepExisting (optional) True to keep existing selections
20316 selectNext : function(keepExisting){
20317 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20318 this.selectRow(this.last+1, keepExisting);
20319 this.grid.getView().focusRow(this.last);
20324 * Selects the row that precedes the last selected row.
20325 * @param {Boolean} keepExisting (optional) True to keep existing selections
20327 selectPrevious : function(keepExisting){
20329 this.selectRow(this.last-1, keepExisting);
20330 this.grid.getView().focusRow(this.last);
20335 * Returns the selected records
20336 * @return {Array} Array of selected records
20338 getSelections : function(){
20339 return [].concat(this.selections.items);
20343 * Returns the first selected record.
20346 getSelected : function(){
20347 return this.selections.itemAt(0);
20352 * Clears all selections.
20354 clearSelections : function(fast){
20355 if(this.locked) return;
20357 var ds = this.grid.dataSource;
20358 var s = this.selections;
20359 s.each(function(r){
20360 this.deselectRow(ds.indexOfId(r.id));
20364 this.selections.clear();
20371 * Selects all rows.
20373 selectAll : function(){
20374 if(this.locked) return;
20375 this.selections.clear();
20376 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20377 this.selectRow(i, true);
20382 * Returns True if there is a selection.
20383 * @return {Boolean}
20385 hasSelection : function(){
20386 return this.selections.length > 0;
20390 * Returns True if the specified row is selected.
20391 * @param {Number/Record} record The record or index of the record to check
20392 * @return {Boolean}
20394 isSelected : function(index){
20395 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20396 return (r && this.selections.key(r.id) ? true : false);
20400 * Returns True if the specified record id is selected.
20401 * @param {String} id The id of record to check
20402 * @return {Boolean}
20404 isIdSelected : function(id){
20405 return (this.selections.key(id) ? true : false);
20409 handleMouseDown : function(e, t){
20410 var view = this.grid.getView(), rowIndex;
20411 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20414 if(e.shiftKey && this.last !== false){
20415 var last = this.last;
20416 this.selectRange(last, rowIndex, e.ctrlKey);
20417 this.last = last; // reset the last
20418 view.focusRow(rowIndex);
20420 var isSelected = this.isSelected(rowIndex);
20421 if(e.button !== 0 && isSelected){
20422 view.focusRow(rowIndex);
20423 }else if(e.ctrlKey && isSelected){
20424 this.deselectRow(rowIndex);
20425 }else if(!isSelected){
20426 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20427 view.focusRow(rowIndex);
20430 this.fireEvent("afterselectionchange", this);
20433 handleDragableRowClick : function(grid, rowIndex, e)
20435 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20436 this.selectRow(rowIndex, false);
20437 grid.view.focusRow(rowIndex);
20438 this.fireEvent("afterselectionchange", this);
20443 * Selects multiple rows.
20444 * @param {Array} rows Array of the indexes of the row to select
20445 * @param {Boolean} keepExisting (optional) True to keep existing selections
20447 selectRows : function(rows, keepExisting){
20449 this.clearSelections();
20451 for(var i = 0, len = rows.length; i < len; i++){
20452 this.selectRow(rows[i], true);
20457 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20458 * @param {Number} startRow The index of the first row in the range
20459 * @param {Number} endRow The index of the last row in the range
20460 * @param {Boolean} keepExisting (optional) True to retain existing selections
20462 selectRange : function(startRow, endRow, keepExisting){
20463 if(this.locked) return;
20465 this.clearSelections();
20467 if(startRow <= endRow){
20468 for(var i = startRow; i <= endRow; i++){
20469 this.selectRow(i, true);
20472 for(var i = startRow; i >= endRow; i--){
20473 this.selectRow(i, true);
20479 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20480 * @param {Number} startRow The index of the first row in the range
20481 * @param {Number} endRow The index of the last row in the range
20483 deselectRange : function(startRow, endRow, preventViewNotify){
20484 if(this.locked) return;
20485 for(var i = startRow; i <= endRow; i++){
20486 this.deselectRow(i, preventViewNotify);
20492 * @param {Number} row The index of the row to select
20493 * @param {Boolean} keepExisting (optional) True to keep existing selections
20495 selectRow : function(index, keepExisting, preventViewNotify){
20496 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20497 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20498 if(!keepExisting || this.singleSelect){
20499 this.clearSelections();
20501 var r = this.grid.dataSource.getAt(index);
20502 this.selections.add(r);
20503 this.last = this.lastActive = index;
20504 if(!preventViewNotify){
20505 this.grid.getView().onRowSelect(index);
20507 this.fireEvent("rowselect", this, index, r);
20508 this.fireEvent("selectionchange", this);
20514 * @param {Number} row The index of the row to deselect
20516 deselectRow : function(index, preventViewNotify){
20517 if(this.locked) return;
20518 if(this.last == index){
20521 if(this.lastActive == index){
20522 this.lastActive = false;
20524 var r = this.grid.dataSource.getAt(index);
20525 this.selections.remove(r);
20526 if(!preventViewNotify){
20527 this.grid.getView().onRowDeselect(index);
20529 this.fireEvent("rowdeselect", this, index);
20530 this.fireEvent("selectionchange", this);
20534 restoreLast : function(){
20536 this.last = this._last;
20541 acceptsNav : function(row, col, cm){
20542 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20546 onEditorKey : function(field, e){
20547 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20552 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20554 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20556 }else if(k == e.ENTER && !e.ctrlKey){
20560 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20562 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20564 }else if(k == e.ESC){
20568 g.startEditing(newCell[0], newCell[1]);
20573 * Ext JS Library 1.1.1
20574 * Copyright(c) 2006-2007, Ext JS, LLC.
20576 * Originally Released Under LGPL - original licence link has changed is not relivant.
20579 * <script type="text/javascript">
20583 * @class Roo.bootstrap.PagingToolbar
20585 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20587 * Create a new PagingToolbar
20588 * @param {Object} config The config object
20590 Roo.bootstrap.PagingToolbar = function(config)
20592 // old args format still supported... - xtype is prefered..
20593 // created from xtype...
20594 var ds = config.dataSource;
20595 this.toolbarItems = [];
20596 if (config.items) {
20597 this.toolbarItems = config.items;
20598 // config.items = [];
20601 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20608 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20612 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20614 * @cfg {Roo.data.Store} dataSource
20615 * The underlying data store providing the paged data
20618 * @cfg {String/HTMLElement/Element} container
20619 * container The id or element that will contain the toolbar
20622 * @cfg {Boolean} displayInfo
20623 * True to display the displayMsg (defaults to false)
20626 * @cfg {Number} pageSize
20627 * The number of records to display per page (defaults to 20)
20631 * @cfg {String} displayMsg
20632 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20634 displayMsg : 'Displaying {0} - {1} of {2}',
20636 * @cfg {String} emptyMsg
20637 * The message to display when no records are found (defaults to "No data to display")
20639 emptyMsg : 'No data to display',
20641 * Customizable piece of the default paging text (defaults to "Page")
20644 beforePageText : "Page",
20646 * Customizable piece of the default paging text (defaults to "of %0")
20649 afterPageText : "of {0}",
20651 * Customizable piece of the default paging text (defaults to "First Page")
20654 firstText : "First Page",
20656 * Customizable piece of the default paging text (defaults to "Previous Page")
20659 prevText : "Previous Page",
20661 * Customizable piece of the default paging text (defaults to "Next Page")
20664 nextText : "Next Page",
20666 * Customizable piece of the default paging text (defaults to "Last Page")
20669 lastText : "Last Page",
20671 * Customizable piece of the default paging text (defaults to "Refresh")
20674 refreshText : "Refresh",
20678 onRender : function(ct, position)
20680 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20681 this.navgroup.parentId = this.id;
20682 this.navgroup.onRender(this.el, null);
20683 // add the buttons to the navgroup
20685 if(this.displayInfo){
20686 Roo.log(this.el.select('ul.navbar-nav',true).first());
20687 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20688 this.displayEl = this.el.select('.x-paging-info', true).first();
20689 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20690 // this.displayEl = navel.el.select('span',true).first();
20696 Roo.each(_this.buttons, function(e){
20697 Roo.factory(e).onRender(_this.el, null);
20701 Roo.each(_this.toolbarItems, function(e) {
20702 _this.navgroup.addItem(e);
20706 this.first = this.navgroup.addItem({
20707 tooltip: this.firstText,
20709 icon : 'fa fa-backward',
20711 preventDefault: true,
20712 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20715 this.prev = this.navgroup.addItem({
20716 tooltip: this.prevText,
20718 icon : 'fa fa-step-backward',
20720 preventDefault: true,
20721 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20723 //this.addSeparator();
20726 var field = this.navgroup.addItem( {
20728 cls : 'x-paging-position',
20730 html : this.beforePageText +
20731 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20732 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20735 this.field = field.el.select('input', true).first();
20736 this.field.on("keydown", this.onPagingKeydown, this);
20737 this.field.on("focus", function(){this.dom.select();});
20740 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20741 //this.field.setHeight(18);
20742 //this.addSeparator();
20743 this.next = this.navgroup.addItem({
20744 tooltip: this.nextText,
20746 html : ' <i class="fa fa-step-forward">',
20748 preventDefault: true,
20749 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20751 this.last = this.navgroup.addItem({
20752 tooltip: this.lastText,
20753 icon : 'fa fa-forward',
20756 preventDefault: true,
20757 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20759 //this.addSeparator();
20760 this.loading = this.navgroup.addItem({
20761 tooltip: this.refreshText,
20762 icon: 'fa fa-refresh',
20763 preventDefault: true,
20764 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20770 updateInfo : function(){
20771 if(this.displayEl){
20772 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20773 var msg = count == 0 ?
20777 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20779 this.displayEl.update(msg);
20784 onLoad : function(ds, r, o){
20785 this.cursor = o.params ? o.params.start : 0;
20786 var d = this.getPageData(),
20790 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20791 this.field.dom.value = ap;
20792 this.first.setDisabled(ap == 1);
20793 this.prev.setDisabled(ap == 1);
20794 this.next.setDisabled(ap == ps);
20795 this.last.setDisabled(ap == ps);
20796 this.loading.enable();
20801 getPageData : function(){
20802 var total = this.ds.getTotalCount();
20805 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20806 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20811 onLoadError : function(){
20812 this.loading.enable();
20816 onPagingKeydown : function(e){
20817 var k = e.getKey();
20818 var d = this.getPageData();
20820 var v = this.field.dom.value, pageNum;
20821 if(!v || isNaN(pageNum = parseInt(v, 10))){
20822 this.field.dom.value = d.activePage;
20825 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20826 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20829 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))
20831 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20832 this.field.dom.value = pageNum;
20833 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20836 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20838 var v = this.field.dom.value, pageNum;
20839 var increment = (e.shiftKey) ? 10 : 1;
20840 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20842 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20843 this.field.dom.value = d.activePage;
20846 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20848 this.field.dom.value = parseInt(v, 10) + increment;
20849 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20850 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20857 beforeLoad : function(){
20859 this.loading.disable();
20864 onClick : function(which){
20873 ds.load({params:{start: 0, limit: this.pageSize}});
20876 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20879 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20882 var total = ds.getTotalCount();
20883 var extra = total % this.pageSize;
20884 var lastStart = extra ? (total - extra) : total-this.pageSize;
20885 ds.load({params:{start: lastStart, limit: this.pageSize}});
20888 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20894 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20895 * @param {Roo.data.Store} store The data store to unbind
20897 unbind : function(ds){
20898 ds.un("beforeload", this.beforeLoad, this);
20899 ds.un("load", this.onLoad, this);
20900 ds.un("loadexception", this.onLoadError, this);
20901 ds.un("remove", this.updateInfo, this);
20902 ds.un("add", this.updateInfo, this);
20903 this.ds = undefined;
20907 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20908 * @param {Roo.data.Store} store The data store to bind
20910 bind : function(ds){
20911 ds.on("beforeload", this.beforeLoad, this);
20912 ds.on("load", this.onLoad, this);
20913 ds.on("loadexception", this.onLoadError, this);
20914 ds.on("remove", this.updateInfo, this);
20915 ds.on("add", this.updateInfo, this);
20926 * @class Roo.bootstrap.MessageBar
20927 * @extends Roo.bootstrap.Component
20928 * Bootstrap MessageBar class
20929 * @cfg {String} html contents of the MessageBar
20930 * @cfg {String} weight (info | success | warning | danger) default info
20931 * @cfg {String} beforeClass insert the bar before the given class
20932 * @cfg {Boolean} closable (true | false) default false
20933 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20936 * Create a new Element
20937 * @param {Object} config The config object
20940 Roo.bootstrap.MessageBar = function(config){
20941 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20944 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20950 beforeClass: 'bootstrap-sticky-wrap',
20952 getAutoCreate : function(){
20956 cls: 'alert alert-dismissable alert-' + this.weight,
20961 html: this.html || ''
20967 cfg.cls += ' alert-messages-fixed';
20981 onRender : function(ct, position)
20983 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20986 var cfg = Roo.apply({}, this.getAutoCreate());
20990 cfg.cls += ' ' + this.cls;
20993 cfg.style = this.style;
20995 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20997 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21000 this.el.select('>button.close').on('click', this.hide, this);
21006 if (!this.rendered) {
21012 this.fireEvent('show', this);
21018 if (!this.rendered) {
21024 this.fireEvent('hide', this);
21027 update : function()
21029 // var e = this.el.dom.firstChild;
21031 // if(this.closable){
21032 // e = e.nextSibling;
21035 // e.data = this.html || '';
21037 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21053 * @class Roo.bootstrap.Graph
21054 * @extends Roo.bootstrap.Component
21055 * Bootstrap Graph class
21059 @cfg {String} graphtype bar | vbar | pie
21060 @cfg {number} g_x coodinator | centre x (pie)
21061 @cfg {number} g_y coodinator | centre y (pie)
21062 @cfg {number} g_r radius (pie)
21063 @cfg {number} g_height height of the chart (respected by all elements in the set)
21064 @cfg {number} g_width width of the chart (respected by all elements in the set)
21065 @cfg {Object} title The title of the chart
21068 -opts (object) options for the chart
21070 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21071 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21073 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.
21074 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21076 o stretch (boolean)
21078 -opts (object) options for the pie
21081 o startAngle (number)
21082 o endAngle (number)
21086 * Create a new Input
21087 * @param {Object} config The config object
21090 Roo.bootstrap.Graph = function(config){
21091 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21097 * The img click event for the img.
21098 * @param {Roo.EventObject} e
21104 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21115 //g_colors: this.colors,
21122 getAutoCreate : function(){
21133 onRender : function(ct,position){
21134 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21135 this.raphael = Raphael(this.el.dom);
21137 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21138 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21139 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21140 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21142 r.text(160, 10, "Single Series Chart").attr(txtattr);
21143 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21144 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21145 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21147 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21148 r.barchart(330, 10, 300, 220, data1);
21149 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21150 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21153 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21154 // r.barchart(30, 30, 560, 250, xdata, {
21155 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21156 // axis : "0 0 1 1",
21157 // axisxlabels : xdata
21158 // //yvalues : cols,
21161 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21163 // this.load(null,xdata,{
21164 // axis : "0 0 1 1",
21165 // axisxlabels : xdata
21170 load : function(graphtype,xdata,opts){
21171 this.raphael.clear();
21173 graphtype = this.graphtype;
21178 var r = this.raphael,
21179 fin = function () {
21180 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21182 fout = function () {
21183 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21185 pfin = function() {
21186 this.sector.stop();
21187 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21190 this.label[0].stop();
21191 this.label[0].attr({ r: 7.5 });
21192 this.label[1].attr({ "font-weight": 800 });
21195 pfout = function() {
21196 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21199 this.label[0].animate({ r: 5 }, 500, "bounce");
21200 this.label[1].attr({ "font-weight": 400 });
21206 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21209 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21212 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21213 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21215 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21222 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21227 setTitle: function(o)
21232 initEvents: function() {
21235 this.el.on('click', this.onClick, this);
21239 onClick : function(e)
21241 Roo.log('img onclick');
21242 this.fireEvent('click', this, e);
21254 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21257 * @class Roo.bootstrap.dash.NumberBox
21258 * @extends Roo.bootstrap.Component
21259 * Bootstrap NumberBox class
21260 * @cfg {String} headline Box headline
21261 * @cfg {String} content Box content
21262 * @cfg {String} icon Box icon
21263 * @cfg {String} footer Footer text
21264 * @cfg {String} fhref Footer href
21267 * Create a new NumberBox
21268 * @param {Object} config The config object
21272 Roo.bootstrap.dash.NumberBox = function(config){
21273 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21277 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21286 getAutoCreate : function(){
21290 cls : 'small-box ',
21298 cls : 'roo-headline',
21299 html : this.headline
21303 cls : 'roo-content',
21304 html : this.content
21318 cls : 'ion ' + this.icon
21327 cls : 'small-box-footer',
21328 href : this.fhref || '#',
21332 cfg.cn.push(footer);
21339 onRender : function(ct,position){
21340 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21347 setHeadline: function (value)
21349 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21352 setFooter: function (value, href)
21354 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21357 this.el.select('a.small-box-footer',true).first().attr('href', href);
21362 setContent: function (value)
21364 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21367 initEvents: function()
21381 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21384 * @class Roo.bootstrap.dash.TabBox
21385 * @extends Roo.bootstrap.Component
21386 * Bootstrap TabBox class
21387 * @cfg {String} title Title of the TabBox
21388 * @cfg {String} icon Icon of the TabBox
21389 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21390 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21393 * Create a new TabBox
21394 * @param {Object} config The config object
21398 Roo.bootstrap.dash.TabBox = function(config){
21399 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21404 * When a pane is added
21405 * @param {Roo.bootstrap.dash.TabPane} pane
21409 * @event activatepane
21410 * When a pane is activated
21411 * @param {Roo.bootstrap.dash.TabPane} pane
21413 "activatepane" : true
21421 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21426 tabScrollable : false,
21428 getChildContainer : function()
21430 return this.el.select('.tab-content', true).first();
21433 getAutoCreate : function(){
21437 cls: 'pull-left header',
21445 cls: 'fa ' + this.icon
21451 cls: 'nav nav-tabs pull-right',
21457 if(this.tabScrollable){
21464 cls: 'nav nav-tabs pull-right',
21475 cls: 'nav-tabs-custom',
21480 cls: 'tab-content no-padding',
21488 initEvents : function()
21490 //Roo.log('add add pane handler');
21491 this.on('addpane', this.onAddPane, this);
21494 * Updates the box title
21495 * @param {String} html to set the title to.
21497 setTitle : function(value)
21499 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21501 onAddPane : function(pane)
21503 this.panes.push(pane);
21504 //Roo.log('addpane');
21506 // tabs are rendere left to right..
21507 if(!this.showtabs){
21511 var ctr = this.el.select('.nav-tabs', true).first();
21514 var existing = ctr.select('.nav-tab',true);
21515 var qty = existing.getCount();;
21518 var tab = ctr.createChild({
21520 cls : 'nav-tab' + (qty ? '' : ' active'),
21528 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21531 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21533 pane.el.addClass('active');
21538 onTabClick : function(ev,un,ob,pane)
21540 //Roo.log('tab - prev default');
21541 ev.preventDefault();
21544 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21545 pane.tab.addClass('active');
21546 //Roo.log(pane.title);
21547 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21548 // technically we should have a deactivate event.. but maybe add later.
21549 // and it should not de-activate the selected tab...
21550 this.fireEvent('activatepane', pane);
21551 pane.el.addClass('active');
21552 pane.fireEvent('activate');
21557 getActivePane : function()
21560 Roo.each(this.panes, function(p) {
21561 if(p.el.hasClass('active')){
21582 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21584 * @class Roo.bootstrap.TabPane
21585 * @extends Roo.bootstrap.Component
21586 * Bootstrap TabPane class
21587 * @cfg {Boolean} active (false | true) Default false
21588 * @cfg {String} title title of panel
21592 * Create a new TabPane
21593 * @param {Object} config The config object
21596 Roo.bootstrap.dash.TabPane = function(config){
21597 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21603 * When a pane is activated
21604 * @param {Roo.bootstrap.dash.TabPane} pane
21611 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21616 // the tabBox that this is attached to.
21619 getAutoCreate : function()
21627 cfg.cls += ' active';
21632 initEvents : function()
21634 //Roo.log('trigger add pane handler');
21635 this.parent().fireEvent('addpane', this)
21639 * Updates the tab title
21640 * @param {String} html to set the title to.
21642 setTitle: function(str)
21648 this.tab.select('a', true).first().dom.innerHTML = str;
21665 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21668 * @class Roo.bootstrap.menu.Menu
21669 * @extends Roo.bootstrap.Component
21670 * Bootstrap Menu class - container for Menu
21671 * @cfg {String} html Text of the menu
21672 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21673 * @cfg {String} icon Font awesome icon
21674 * @cfg {String} pos Menu align to (top | bottom) default bottom
21678 * Create a new Menu
21679 * @param {Object} config The config object
21683 Roo.bootstrap.menu.Menu = function(config){
21684 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21688 * @event beforeshow
21689 * Fires before this menu is displayed
21690 * @param {Roo.bootstrap.menu.Menu} this
21694 * @event beforehide
21695 * Fires before this menu is hidden
21696 * @param {Roo.bootstrap.menu.Menu} this
21701 * Fires after this menu is displayed
21702 * @param {Roo.bootstrap.menu.Menu} this
21707 * Fires after this menu is hidden
21708 * @param {Roo.bootstrap.menu.Menu} this
21713 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21714 * @param {Roo.bootstrap.menu.Menu} this
21715 * @param {Roo.EventObject} e
21722 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21726 weight : 'default',
21731 getChildContainer : function() {
21732 if(this.isSubMenu){
21736 return this.el.select('ul.dropdown-menu', true).first();
21739 getAutoCreate : function()
21744 cls : 'roo-menu-text',
21752 cls : 'fa ' + this.icon
21763 cls : 'dropdown-button btn btn-' + this.weight,
21768 cls : 'dropdown-toggle btn btn-' + this.weight,
21778 cls : 'dropdown-menu'
21784 if(this.pos == 'top'){
21785 cfg.cls += ' dropup';
21788 if(this.isSubMenu){
21791 cls : 'dropdown-menu'
21798 onRender : function(ct, position)
21800 this.isSubMenu = ct.hasClass('dropdown-submenu');
21802 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21805 initEvents : function()
21807 if(this.isSubMenu){
21811 this.hidden = true;
21813 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21814 this.triggerEl.on('click', this.onTriggerPress, this);
21816 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21817 this.buttonEl.on('click', this.onClick, this);
21823 if(this.isSubMenu){
21827 return this.el.select('ul.dropdown-menu', true).first();
21830 onClick : function(e)
21832 this.fireEvent("click", this, e);
21835 onTriggerPress : function(e)
21837 if (this.isVisible()) {
21844 isVisible : function(){
21845 return !this.hidden;
21850 this.fireEvent("beforeshow", this);
21852 this.hidden = false;
21853 this.el.addClass('open');
21855 Roo.get(document).on("mouseup", this.onMouseUp, this);
21857 this.fireEvent("show", this);
21864 this.fireEvent("beforehide", this);
21866 this.hidden = true;
21867 this.el.removeClass('open');
21869 Roo.get(document).un("mouseup", this.onMouseUp);
21871 this.fireEvent("hide", this);
21874 onMouseUp : function()
21888 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21891 * @class Roo.bootstrap.menu.Item
21892 * @extends Roo.bootstrap.Component
21893 * Bootstrap MenuItem class
21894 * @cfg {Boolean} submenu (true | false) default false
21895 * @cfg {String} html text of the item
21896 * @cfg {String} href the link
21897 * @cfg {Boolean} disable (true | false) default false
21898 * @cfg {Boolean} preventDefault (true | false) default true
21899 * @cfg {String} icon Font awesome icon
21900 * @cfg {String} pos Submenu align to (left | right) default right
21904 * Create a new Item
21905 * @param {Object} config The config object
21909 Roo.bootstrap.menu.Item = function(config){
21910 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21914 * Fires when the mouse is hovering over this menu
21915 * @param {Roo.bootstrap.menu.Item} this
21916 * @param {Roo.EventObject} e
21921 * Fires when the mouse exits this menu
21922 * @param {Roo.bootstrap.menu.Item} this
21923 * @param {Roo.EventObject} e
21929 * The raw click event for the entire grid.
21930 * @param {Roo.EventObject} e
21936 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21941 preventDefault: true,
21946 getAutoCreate : function()
21951 cls : 'roo-menu-item-text',
21959 cls : 'fa ' + this.icon
21968 href : this.href || '#',
21975 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21979 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21981 if(this.pos == 'left'){
21982 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21989 initEvents : function()
21991 this.el.on('mouseover', this.onMouseOver, this);
21992 this.el.on('mouseout', this.onMouseOut, this);
21994 this.el.select('a', true).first().on('click', this.onClick, this);
21998 onClick : function(e)
22000 if(this.preventDefault){
22001 e.preventDefault();
22004 this.fireEvent("click", this, e);
22007 onMouseOver : function(e)
22009 if(this.submenu && this.pos == 'left'){
22010 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22013 this.fireEvent("mouseover", this, e);
22016 onMouseOut : function(e)
22018 this.fireEvent("mouseout", this, e);
22030 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22033 * @class Roo.bootstrap.menu.Separator
22034 * @extends Roo.bootstrap.Component
22035 * Bootstrap Separator class
22038 * Create a new Separator
22039 * @param {Object} config The config object
22043 Roo.bootstrap.menu.Separator = function(config){
22044 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22047 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22049 getAutoCreate : function(){
22070 * @class Roo.bootstrap.Tooltip
22071 * Bootstrap Tooltip class
22072 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22073 * to determine which dom element triggers the tooltip.
22075 * It needs to add support for additional attributes like tooltip-position
22078 * Create a new Toolti
22079 * @param {Object} config The config object
22082 Roo.bootstrap.Tooltip = function(config){
22083 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22086 Roo.apply(Roo.bootstrap.Tooltip, {
22088 * @function init initialize tooltip monitoring.
22092 currentTip : false,
22093 currentRegion : false,
22099 Roo.get(document).on('mouseover', this.enter ,this);
22100 Roo.get(document).on('mouseout', this.leave, this);
22103 this.currentTip = new Roo.bootstrap.Tooltip();
22106 enter : function(ev)
22108 var dom = ev.getTarget();
22110 //Roo.log(['enter',dom]);
22111 var el = Roo.fly(dom);
22112 if (this.currentEl) {
22114 //Roo.log(this.currentEl);
22115 //Roo.log(this.currentEl.contains(dom));
22116 if (this.currentEl == el) {
22119 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22127 if (this.currentTip.el) {
22128 this.currentTip.el.hide(); // force hiding...
22133 // you can not look for children, as if el is the body.. then everythign is the child..
22134 if (!el.attr('tooltip')) { //
22135 if (!el.select("[tooltip]").elements.length) {
22138 // is the mouse over this child...?
22139 bindEl = el.select("[tooltip]").first();
22140 var xy = ev.getXY();
22141 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22142 //Roo.log("not in region.");
22145 //Roo.log("child element over..");
22148 this.currentEl = bindEl;
22149 this.currentTip.bind(bindEl);
22150 this.currentRegion = Roo.lib.Region.getRegion(dom);
22151 this.currentTip.enter();
22154 leave : function(ev)
22156 var dom = ev.getTarget();
22157 //Roo.log(['leave',dom]);
22158 if (!this.currentEl) {
22163 if (dom != this.currentEl.dom) {
22166 var xy = ev.getXY();
22167 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22170 // only activate leave if mouse cursor is outside... bounding box..
22175 if (this.currentTip) {
22176 this.currentTip.leave();
22178 //Roo.log('clear currentEl');
22179 this.currentEl = false;
22184 'left' : ['r-l', [-2,0], 'right'],
22185 'right' : ['l-r', [2,0], 'left'],
22186 'bottom' : ['t-b', [0,2], 'top'],
22187 'top' : [ 'b-t', [0,-2], 'bottom']
22193 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22198 delay : null, // can be { show : 300 , hide: 500}
22202 hoverState : null, //???
22204 placement : 'bottom',
22206 getAutoCreate : function(){
22213 cls : 'tooltip-arrow'
22216 cls : 'tooltip-inner'
22223 bind : function(el)
22229 enter : function () {
22231 if (this.timeout != null) {
22232 clearTimeout(this.timeout);
22235 this.hoverState = 'in';
22236 //Roo.log("enter - show");
22237 if (!this.delay || !this.delay.show) {
22242 this.timeout = setTimeout(function () {
22243 if (_t.hoverState == 'in') {
22246 }, this.delay.show);
22250 clearTimeout(this.timeout);
22252 this.hoverState = 'out';
22253 if (!this.delay || !this.delay.hide) {
22259 this.timeout = setTimeout(function () {
22260 //Roo.log("leave - timeout");
22262 if (_t.hoverState == 'out') {
22264 Roo.bootstrap.Tooltip.currentEl = false;
22272 this.render(document.body);
22275 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22277 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22279 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22281 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22283 var placement = typeof this.placement == 'function' ?
22284 this.placement.call(this, this.el, on_el) :
22287 var autoToken = /\s?auto?\s?/i;
22288 var autoPlace = autoToken.test(placement);
22290 placement = placement.replace(autoToken, '') || 'top';
22294 //this.el.setXY([0,0]);
22296 //this.el.dom.style.display='block';
22297 this.el.addClass(placement);
22299 //this.el.appendTo(on_el);
22301 var p = this.getPosition();
22302 var box = this.el.getBox();
22307 var align = Roo.bootstrap.Tooltip.alignment[placement];
22308 this.el.alignTo(this.bindEl, align[0],align[1]);
22309 //var arrow = this.el.select('.arrow',true).first();
22310 //arrow.set(align[2],
22312 this.el.addClass('in fade');
22313 this.hoverState = null;
22315 if (this.el.hasClass('fade')) {
22326 //this.el.setXY([0,0]);
22327 this.el.removeClass('in');
22343 * @class Roo.bootstrap.LocationPicker
22344 * @extends Roo.bootstrap.Component
22345 * Bootstrap LocationPicker class
22346 * @cfg {Number} latitude Position when init default 0
22347 * @cfg {Number} longitude Position when init default 0
22348 * @cfg {Number} zoom default 15
22349 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22350 * @cfg {Boolean} mapTypeControl default false
22351 * @cfg {Boolean} disableDoubleClickZoom default false
22352 * @cfg {Boolean} scrollwheel default true
22353 * @cfg {Boolean} streetViewControl default false
22354 * @cfg {Number} radius default 0
22355 * @cfg {String} locationName
22356 * @cfg {Boolean} draggable default true
22357 * @cfg {Boolean} enableAutocomplete default false
22358 * @cfg {Boolean} enableReverseGeocode default true
22359 * @cfg {String} markerTitle
22362 * Create a new LocationPicker
22363 * @param {Object} config The config object
22367 Roo.bootstrap.LocationPicker = function(config){
22369 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22374 * Fires when the picker initialized.
22375 * @param {Roo.bootstrap.LocationPicker} this
22376 * @param {Google Location} location
22380 * @event positionchanged
22381 * Fires when the picker position changed.
22382 * @param {Roo.bootstrap.LocationPicker} this
22383 * @param {Google Location} location
22385 positionchanged : true,
22388 * Fires when the map resize.
22389 * @param {Roo.bootstrap.LocationPicker} this
22394 * Fires when the map show.
22395 * @param {Roo.bootstrap.LocationPicker} this
22400 * Fires when the map hide.
22401 * @param {Roo.bootstrap.LocationPicker} this
22406 * Fires when click the map.
22407 * @param {Roo.bootstrap.LocationPicker} this
22408 * @param {Map event} e
22412 * @event mapRightClick
22413 * Fires when right click the map.
22414 * @param {Roo.bootstrap.LocationPicker} this
22415 * @param {Map event} e
22417 mapRightClick : true,
22419 * @event markerClick
22420 * Fires when click the marker.
22421 * @param {Roo.bootstrap.LocationPicker} this
22422 * @param {Map event} e
22424 markerClick : true,
22426 * @event markerRightClick
22427 * Fires when right click the marker.
22428 * @param {Roo.bootstrap.LocationPicker} this
22429 * @param {Map event} e
22431 markerRightClick : true,
22433 * @event OverlayViewDraw
22434 * Fires when OverlayView Draw
22435 * @param {Roo.bootstrap.LocationPicker} this
22437 OverlayViewDraw : true,
22439 * @event OverlayViewOnAdd
22440 * Fires when OverlayView Draw
22441 * @param {Roo.bootstrap.LocationPicker} this
22443 OverlayViewOnAdd : true,
22445 * @event OverlayViewOnRemove
22446 * Fires when OverlayView Draw
22447 * @param {Roo.bootstrap.LocationPicker} this
22449 OverlayViewOnRemove : true,
22451 * @event OverlayViewShow
22452 * Fires when OverlayView Draw
22453 * @param {Roo.bootstrap.LocationPicker} this
22454 * @param {Pixel} cpx
22456 OverlayViewShow : true,
22458 * @event OverlayViewHide
22459 * Fires when OverlayView Draw
22460 * @param {Roo.bootstrap.LocationPicker} this
22462 OverlayViewHide : true
22467 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22469 gMapContext: false,
22475 mapTypeControl: false,
22476 disableDoubleClickZoom: false,
22478 streetViewControl: false,
22482 enableAutocomplete: false,
22483 enableReverseGeocode: true,
22486 getAutoCreate: function()
22491 cls: 'roo-location-picker'
22497 initEvents: function(ct, position)
22499 if(!this.el.getWidth() || this.isApplied()){
22503 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22508 initial: function()
22510 if(!this.mapTypeId){
22511 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22514 this.gMapContext = this.GMapContext();
22516 this.initOverlayView();
22518 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22522 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22523 _this.setPosition(_this.gMapContext.marker.position);
22526 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22527 _this.fireEvent('mapClick', this, event);
22531 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22532 _this.fireEvent('mapRightClick', this, event);
22536 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22537 _this.fireEvent('markerClick', this, event);
22541 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22542 _this.fireEvent('markerRightClick', this, event);
22546 this.setPosition(this.gMapContext.location);
22548 this.fireEvent('initial', this, this.gMapContext.location);
22551 initOverlayView: function()
22555 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22559 _this.fireEvent('OverlayViewDraw', _this);
22564 _this.fireEvent('OverlayViewOnAdd', _this);
22567 onRemove: function()
22569 _this.fireEvent('OverlayViewOnRemove', _this);
22572 show: function(cpx)
22574 _this.fireEvent('OverlayViewShow', _this, cpx);
22579 _this.fireEvent('OverlayViewHide', _this);
22585 fromLatLngToContainerPixel: function(event)
22587 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22590 isApplied: function()
22592 return this.getGmapContext() == false ? false : true;
22595 getGmapContext: function()
22597 return this.gMapContext
22600 GMapContext: function()
22602 var position = new google.maps.LatLng(this.latitude, this.longitude);
22604 var _map = new google.maps.Map(this.el.dom, {
22607 mapTypeId: this.mapTypeId,
22608 mapTypeControl: this.mapTypeControl,
22609 disableDoubleClickZoom: this.disableDoubleClickZoom,
22610 scrollwheel: this.scrollwheel,
22611 streetViewControl: this.streetViewControl,
22612 locationName: this.locationName,
22613 draggable: this.draggable,
22614 enableAutocomplete: this.enableAutocomplete,
22615 enableReverseGeocode: this.enableReverseGeocode
22618 var _marker = new google.maps.Marker({
22619 position: position,
22621 title: this.markerTitle,
22622 draggable: this.draggable
22629 location: position,
22630 radius: this.radius,
22631 locationName: this.locationName,
22632 addressComponents: {
22633 formatted_address: null,
22634 addressLine1: null,
22635 addressLine2: null,
22637 streetNumber: null,
22641 stateOrProvince: null
22644 domContainer: this.el.dom,
22645 geodecoder: new google.maps.Geocoder()
22649 drawCircle: function(center, radius, options)
22651 if (this.gMapContext.circle != null) {
22652 this.gMapContext.circle.setMap(null);
22656 options = Roo.apply({}, options, {
22657 strokeColor: "#0000FF",
22658 strokeOpacity: .35,
22660 fillColor: "#0000FF",
22664 options.map = this.gMapContext.map;
22665 options.radius = radius;
22666 options.center = center;
22667 this.gMapContext.circle = new google.maps.Circle(options);
22668 return this.gMapContext.circle;
22674 setPosition: function(location)
22676 this.gMapContext.location = location;
22677 this.gMapContext.marker.setPosition(location);
22678 this.gMapContext.map.panTo(location);
22679 this.drawCircle(location, this.gMapContext.radius, {});
22683 if (this.gMapContext.settings.enableReverseGeocode) {
22684 this.gMapContext.geodecoder.geocode({
22685 latLng: this.gMapContext.location
22686 }, function(results, status) {
22688 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22689 _this.gMapContext.locationName = results[0].formatted_address;
22690 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22692 _this.fireEvent('positionchanged', this, location);
22699 this.fireEvent('positionchanged', this, location);
22704 google.maps.event.trigger(this.gMapContext.map, "resize");
22706 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22708 this.fireEvent('resize', this);
22711 setPositionByLatLng: function(latitude, longitude)
22713 this.setPosition(new google.maps.LatLng(latitude, longitude));
22716 getCurrentPosition: function()
22719 latitude: this.gMapContext.location.lat(),
22720 longitude: this.gMapContext.location.lng()
22724 getAddressName: function()
22726 return this.gMapContext.locationName;
22729 getAddressComponents: function()
22731 return this.gMapContext.addressComponents;
22734 address_component_from_google_geocode: function(address_components)
22738 for (var i = 0; i < address_components.length; i++) {
22739 var component = address_components[i];
22740 if (component.types.indexOf("postal_code") >= 0) {
22741 result.postalCode = component.short_name;
22742 } else if (component.types.indexOf("street_number") >= 0) {
22743 result.streetNumber = component.short_name;
22744 } else if (component.types.indexOf("route") >= 0) {
22745 result.streetName = component.short_name;
22746 } else if (component.types.indexOf("neighborhood") >= 0) {
22747 result.city = component.short_name;
22748 } else if (component.types.indexOf("locality") >= 0) {
22749 result.city = component.short_name;
22750 } else if (component.types.indexOf("sublocality") >= 0) {
22751 result.district = component.short_name;
22752 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22753 result.stateOrProvince = component.short_name;
22754 } else if (component.types.indexOf("country") >= 0) {
22755 result.country = component.short_name;
22759 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22760 result.addressLine2 = "";
22764 setZoomLevel: function(zoom)
22766 this.gMapContext.map.setZoom(zoom);
22779 this.fireEvent('show', this);
22790 this.fireEvent('hide', this);
22795 Roo.apply(Roo.bootstrap.LocationPicker, {
22797 OverlayView : function(map, options)
22799 options = options || {};
22813 * @class Roo.bootstrap.Alert
22814 * @extends Roo.bootstrap.Component
22815 * Bootstrap Alert class
22816 * @cfg {String} title The title of alert
22817 * @cfg {String} html The content of alert
22818 * @cfg {String} weight ( success | info | warning | danger )
22819 * @cfg {String} faicon font-awesomeicon
22822 * Create a new alert
22823 * @param {Object} config The config object
22827 Roo.bootstrap.Alert = function(config){
22828 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22832 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22839 getAutoCreate : function()
22848 cls : 'roo-alert-icon'
22853 cls : 'roo-alert-title',
22858 cls : 'roo-alert-text',
22865 cfg.cn[0].cls += ' fa ' + this.faicon;
22869 cfg.cls += ' alert-' + this.weight;
22875 initEvents: function()
22877 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22880 setTitle : function(str)
22882 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22885 setText : function(str)
22887 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22890 setWeight : function(weight)
22893 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22896 this.weight = weight;
22898 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22901 setIcon : function(icon)
22904 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22909 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);