4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
19 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
23 * Do not use directly - it does not do anything..
24 * @param {Object} config The config object
29 Roo.bootstrap.Component = function(config){
30 Roo.bootstrap.Component.superclass.constructor.call(this, config);
34 * @event childrenrendered
35 * Fires when the children have been rendered..
36 * @param {Roo.bootstrap.Component} this
38 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
106 // fill in the extra attributes
107 if (this.xattr && typeof(this.xattr) =='object') {
108 for (var i in this.xattr) {
109 cfg[i] = this.xattr[i];
114 cfg.dataId = this.dataId;
118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121 if (this.style) { // fixme needs to support more complex style data.
122 cfg.style = this.style;
126 cfg.name = this.name;
131 this.el = ct.createChild(cfg, position);
134 this.tooltipEl().attr('tooltip', this.tooltip);
137 if(this.tabIndex !== undefined){
138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
145 * Fetch the element to add children to
146 * @return {Roo.Element} defaults to this.el
148 getChildContainer : function()
153 * Fetch the element to display the tooltip on.
154 * @return {Roo.Element} defaults to this.el
156 tooltipEl : function()
161 addxtype : function(tree,cntr)
165 cn = Roo.factory(tree);
167 cn.parentType = this.xtype; //??
168 cn.parentId = this.id;
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171 if (typeof(cn.container_method) == 'string') {
172 cntr = cn.container_method;
176 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
178 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
180 var build_from_html = Roo.XComponent.build_from_html;
182 var is_body = (tree.xtype == 'Body') ;
184 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186 var self_cntr_el = Roo.get(this[cntr](false));
188 // do not try and build conditional elements
189 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
193 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195 return this.addxtypeChild(tree,cntr);
198 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
201 return this.addxtypeChild(Roo.apply({}, tree),cntr);
204 Roo.log('skipping render');
210 if (!build_from_html) {
214 // this i think handles overlaying multiple children of the same type
215 // with the sam eelement.. - which might be buggy..
217 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
223 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
227 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
232 addxtypeChild : function (tree, cntr)
234 Roo.debug && Roo.log('addxtypeChild:' + cntr);
236 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
239 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
240 (typeof(tree['flexy:foreach']) != 'undefined');
244 skip_children = false;
245 // render the element if it's not BODY.
246 if (tree.xtype != 'Body') {
248 cn = Roo.factory(tree);
250 cn.parentType = this.xtype; //??
251 cn.parentId = this.id;
253 var build_from_html = Roo.XComponent.build_from_html;
256 // does the container contain child eleemnts with 'xtype' attributes.
257 // that match this xtype..
258 // note - when we render we create these as well..
259 // so we should check to see if body has xtype set.
260 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
262 var self_cntr_el = Roo.get(this[cntr](false));
263 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
265 Roo.log(Roo.XComponent.build_from_html);
266 Roo.log("got echild:");
269 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
270 // and are not displayed -this causes this to use up the wrong element when matching.
271 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
274 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
275 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
281 //echild.dom.removeAttribute('xtype');
283 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
284 Roo.debug && Roo.log(self_cntr_el);
285 Roo.debug && Roo.log(echild);
286 Roo.debug && Roo.log(cn);
292 // if object has flexy:if - then it may or may not be rendered.
293 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
294 // skip a flexy if element.
295 Roo.debug && Roo.log('skipping render');
296 Roo.debug && Roo.log(tree);
298 Roo.debug && Roo.log('skipping all children');
299 skip_children = true;
304 // actually if flexy:foreach is found, we really want to create
305 // multiple copies here...
307 //Roo.log(this[cntr]());
308 cn.render(this[cntr](true));
310 // then add the element..
318 if (typeof (tree.menu) != 'undefined') {
319 tree.menu.parentType = cn.xtype;
320 tree.menu.triggerEl = cn.el;
321 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
325 if (!tree.items || !tree.items.length) {
329 var items = tree.items;
332 //Roo.log(items.length);
334 if (!skip_children) {
335 for(var i =0;i < items.length;i++) {
336 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
342 this.fireEvent('childrenrendered', this);
358 * @class Roo.bootstrap.Body
359 * @extends Roo.bootstrap.Component
360 * Bootstrap Body class
364 * @param {Object} config The config object
367 Roo.bootstrap.Body = function(config){
368 Roo.bootstrap.Body.superclass.constructor.call(this, config);
369 this.el = Roo.get(document.body);
370 if (this.cls && this.cls.length) {
371 Roo.get(document.body).addClass(this.cls);
375 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
380 onRender : function(ct, position)
382 /* Roo.log("Roo.bootstrap.Body - onRender");
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
404 * @class Roo.bootstrap.ButtonGroup
405 * @extends Roo.bootstrap.Component
406 * Bootstrap ButtonGroup class
407 * @cfg {String} size lg | sm | xs (default empty normal)
408 * @cfg {String} align vertical | justified (default none)
409 * @cfg {String} direction up | down (default down)
410 * @cfg {Boolean} toolbar false | true
411 * @cfg {Boolean} btn true | false
416 * @param {Object} config The config object
419 Roo.bootstrap.ButtonGroup = function(config){
420 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
423 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
431 getAutoCreate : function(){
437 cfg.html = this.html || cfg.html;
448 if (['vertical','justified'].indexOf(this.align)!==-1) {
449 cfg.cls = 'btn-group-' + this.align;
451 if (this.align == 'justified') {
452 console.log(this.items);
456 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
457 cfg.cls += ' btn-group-' + this.size;
460 if (this.direction == 'up') {
461 cfg.cls += ' dropup' ;
477 * @class Roo.bootstrap.Button
478 * @extends Roo.bootstrap.Component
479 * Bootstrap Button class
480 * @cfg {String} html The button content
481 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
482 * @cfg {String} size ( lg | sm | xs)
483 * @cfg {String} tag ( a | input | submit)
484 * @cfg {String} href empty or href
485 * @cfg {Boolean} disabled default false;
486 * @cfg {Boolean} isClose default false;
487 * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
488 * @cfg {String} badge text for badge
489 * @cfg {String} theme default
490 * @cfg {Boolean} inverse
491 * @cfg {Boolean} toggle
492 * @cfg {String} ontext text for on toggle state
493 * @cfg {String} offtext text for off toggle state
494 * @cfg {Boolean} defaulton
495 * @cfg {Boolean} preventDefault default true
496 * @cfg {Boolean} removeClass remove the standard class..
497 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
500 * Create a new button
501 * @param {Object} config The config object
505 Roo.bootstrap.Button = function(config){
506 Roo.bootstrap.Button.superclass.constructor.call(this, config);
511 * When a butotn is pressed
512 * @param {Roo.bootstrap.Button} this
513 * @param {Roo.EventObject} e
518 * After the button has been toggles
519 * @param {Roo.EventObject} e
520 * @param {boolean} pressed (also available as button.pressed)
526 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
544 preventDefault: true,
553 getAutoCreate : function(){
561 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
562 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
567 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
569 if (this.toggle == true) {
572 cls: 'slider-frame roo-button',
577 'data-off-text':'OFF',
578 cls: 'slider-button',
584 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585 cfg.cls += ' '+this.weight;
594 cfg["aria-hidden"] = true;
596 cfg.html = "×";
602 if (this.theme==='default') {
603 cfg.cls = 'btn roo-button';
605 //if (this.parentType != 'Navbar') {
606 this.weight = this.weight.length ? this.weight : 'default';
608 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
610 cfg.cls += ' btn-' + this.weight;
612 } else if (this.theme==='glow') {
615 cfg.cls = 'btn-glow roo-button';
617 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
619 cfg.cls += ' ' + this.weight;
625 this.cls += ' inverse';
630 cfg.cls += ' active';
634 cfg.disabled = 'disabled';
638 Roo.log('changing to ul' );
640 this.glyphicon = 'caret';
643 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
645 //gsRoo.log(this.parentType);
646 if (this.parentType === 'Navbar' && !this.parent().bar) {
647 Roo.log('changing to li?');
656 href : this.href || '#'
659 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
660 cfg.cls += ' dropdown';
667 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
669 if (this.glyphicon) {
670 cfg.html = ' ' + cfg.html;
675 cls: 'glyphicon glyphicon-' + this.glyphicon
685 // cfg.cls='btn roo-button';
689 var value = cfg.html;
694 cls: 'glyphicon glyphicon-' + this.glyphicon,
713 cfg.cls += ' dropdown';
714 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
717 if (cfg.tag !== 'a' && this.href !== '') {
718 throw "Tag must be a to set href.";
719 } else if (this.href.length > 0) {
720 cfg.href = this.href;
723 if(this.removeClass){
728 cfg.target = this.target;
733 initEvents: function() {
734 // Roo.log('init events?');
735 // Roo.log(this.el.dom);
738 if (typeof (this.menu) != 'undefined') {
739 this.menu.parentType = this.xtype;
740 this.menu.triggerEl = this.el;
741 this.addxtype(Roo.apply({}, this.menu));
745 if (this.el.hasClass('roo-button')) {
746 this.el.on('click', this.onClick, this);
748 this.el.select('.roo-button').on('click', this.onClick, this);
751 if(this.removeClass){
752 this.el.on('click', this.onClick, this);
755 this.el.enableDisplayMode();
758 onClick : function(e)
765 Roo.log('button on click ');
766 if(this.preventDefault){
769 if (this.pressed === true || this.pressed === false) {
770 this.pressed = !this.pressed;
771 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
772 this.fireEvent('toggle', this, e, this.pressed);
776 this.fireEvent('click', this, e);
780 * Enables this button
784 this.disabled = false;
785 this.el.removeClass('disabled');
789 * Disable this button
793 this.disabled = true;
794 this.el.addClass('disabled');
797 * sets the active state on/off,
798 * @param {Boolean} state (optional) Force a particular state
800 setActive : function(v) {
802 this.el[v ? 'addClass' : 'removeClass']('active');
805 * toggles the current active state
807 toggleActive : function()
809 var active = this.el.hasClass('active');
810 this.setActive(!active);
814 setText : function(str)
816 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
820 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
843 * @class Roo.bootstrap.Column
844 * @extends Roo.bootstrap.Component
845 * Bootstrap Column class
846 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
847 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
848 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
849 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
850 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
851 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
852 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
853 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
856 * @cfg {Boolean} hidden (true|false) hide the element
857 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
858 * @cfg {String} fa (ban|check|...) font awesome icon
859 * @cfg {Number} fasize (1|2|....) font awsome size
861 * @cfg {String} icon (info-sign|check|...) glyphicon name
863 * @cfg {String} html content of column.
866 * Create a new Column
867 * @param {Object} config The config object
870 Roo.bootstrap.Column = function(config){
871 Roo.bootstrap.Column.superclass.constructor.call(this, config);
874 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
892 getAutoCreate : function(){
893 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
901 ['xs','sm','md','lg'].map(function(size){
902 //Roo.log( size + ':' + settings[size]);
904 if (settings[size+'off'] !== false) {
905 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
908 if (settings[size] === false) {
911 Roo.log(settings[size]);
912 if (!settings[size]) { // 0 = hidden
913 cfg.cls += ' hidden-' + size;
916 cfg.cls += ' col-' + size + '-' + settings[size];
921 cfg.cls += ' hidden';
924 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
925 cfg.cls +=' alert alert-' + this.alert;
929 if (this.html.length) {
930 cfg.html = this.html;
934 if (this.fasize > 1) {
935 fasize = ' fa-' + this.fasize + 'x';
937 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
942 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
961 * @class Roo.bootstrap.Container
962 * @extends Roo.bootstrap.Component
963 * Bootstrap Container class
964 * @cfg {Boolean} jumbotron is it a jumbotron element
965 * @cfg {String} html content of element
966 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
967 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
968 * @cfg {String} header content of header (for panel)
969 * @cfg {String} footer content of footer (for panel)
970 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
971 * @cfg {String} tag (header|aside|section) type of HTML tag.
972 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
973 * @cfg {String} fa (ban|check|...) font awesome icon
974 * @cfg {String} icon (info-sign|check|...) glyphicon name
975 * @cfg {Boolean} hidden (true|false) hide the element
979 * Create a new Container
980 * @param {Object} config The config object
983 Roo.bootstrap.Container = function(config){
984 Roo.bootstrap.Container.superclass.constructor.call(this, config);
987 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1001 getChildContainer : function() {
1007 if (this.panel.length) {
1008 return this.el.select('.panel-body',true).first();
1015 getAutoCreate : function(){
1018 tag : this.tag || 'div',
1022 if (this.jumbotron) {
1023 cfg.cls = 'jumbotron';
1028 // - this is applied by the parent..
1030 // cfg.cls = this.cls + '';
1033 if (this.sticky.length) {
1035 var bd = Roo.get(document.body);
1036 if (!bd.hasClass('bootstrap-sticky')) {
1037 bd.addClass('bootstrap-sticky');
1038 Roo.select('html',true).setStyle('height', '100%');
1041 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1045 if (this.well.length) {
1046 switch (this.well) {
1049 cfg.cls +=' well well-' +this.well;
1058 cfg.cls += ' hidden';
1062 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1063 cfg.cls +=' alert alert-' + this.alert;
1068 if (this.panel.length) {
1069 cfg.cls += ' panel panel-' + this.panel;
1071 if (this.header.length) {
1074 cls : 'panel-heading',
1077 cls : 'panel-title',
1090 if (this.footer.length) {
1092 cls : 'panel-footer',
1101 body.html = this.html || cfg.html;
1102 // prefix with the icons..
1104 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1107 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1112 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1113 cfg.cls = 'container';
1119 titleEl : function()
1121 if(!this.el || !this.panel.length || !this.header.length){
1125 return this.el.select('.panel-title',true).first();
1128 setTitle : function(v)
1130 var titleEl = this.titleEl();
1136 titleEl.dom.innerHTML = v;
1139 getTitle : function()
1142 var titleEl = this.titleEl();
1148 return titleEl.dom.innerHTML;
1152 this.el.removeClass('hidden');
1155 if (!this.el.hasClass('hidden')) {
1156 this.el.addClass('hidden');
1172 * @class Roo.bootstrap.Img
1173 * @extends Roo.bootstrap.Component
1174 * Bootstrap Img class
1175 * @cfg {Boolean} imgResponsive false | true
1176 * @cfg {String} border rounded | circle | thumbnail
1177 * @cfg {String} src image source
1178 * @cfg {String} alt image alternative text
1179 * @cfg {String} href a tag href
1180 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1183 * Create a new Input
1184 * @param {Object} config The config object
1187 Roo.bootstrap.Img = function(config){
1188 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1194 * The img click event for the img.
1195 * @param {Roo.EventObject} e
1201 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1203 imgResponsive: true,
1209 getAutoCreate : function(){
1213 cls: (this.imgResponsive) ? 'img-responsive' : '',
1217 cfg.html = this.html || cfg.html;
1219 cfg.src = this.src || cfg.src;
1221 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1222 cfg.cls += ' img-' + this.border;
1239 a.target = this.target;
1245 return (this.href) ? a : cfg;
1248 initEvents: function() {
1251 this.el.on('click', this.onClick, this);
1255 onClick : function(e)
1257 Roo.log('img onclick');
1258 this.fireEvent('click', this, e);
1272 * @class Roo.bootstrap.Link
1273 * @extends Roo.bootstrap.Component
1274 * Bootstrap Link Class
1275 * @cfg {String} alt image alternative text
1276 * @cfg {String} href a tag href
1277 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1278 * @cfg {String} html the content of the link.
1279 * @cfg {String} anchor name for the anchor link
1281 * @cfg {Boolean} preventDefault (true | false) default false
1285 * Create a new Input
1286 * @param {Object} config The config object
1289 Roo.bootstrap.Link = function(config){
1290 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1296 * The img click event for the img.
1297 * @param {Roo.EventObject} e
1303 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1307 preventDefault: false,
1311 getAutoCreate : function()
1317 // anchor's do not require html/href...
1318 if (this.anchor === false) {
1319 cfg.html = this.html || 'html-missing';
1320 cfg.href = this.href || '#';
1322 cfg.name = this.anchor;
1323 if (this.html !== false) {
1324 cfg.html = this.html;
1326 if (this.href !== false) {
1327 cfg.href = this.href;
1331 if(this.alt !== false){
1336 if(this.target !== false) {
1337 cfg.target = this.target;
1343 initEvents: function() {
1345 if(!this.href || this.preventDefault){
1346 this.el.on('click', this.onClick, this);
1350 onClick : function(e)
1352 if(this.preventDefault){
1355 //Roo.log('img onclick');
1356 this.fireEvent('click', this, e);
1369 * @class Roo.bootstrap.Header
1370 * @extends Roo.bootstrap.Component
1371 * Bootstrap Header class
1372 * @cfg {String} html content of header
1373 * @cfg {Number} level (1|2|3|4|5|6) default 1
1376 * Create a new Header
1377 * @param {Object} config The config object
1381 Roo.bootstrap.Header = function(config){
1382 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1385 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1393 getAutoCreate : function(){
1398 tag: 'h' + (1 *this.level),
1399 html: this.html || ''
1411 * Ext JS Library 1.1.1
1412 * Copyright(c) 2006-2007, Ext JS, LLC.
1414 * Originally Released Under LGPL - original licence link has changed is not relivant.
1417 * <script type="text/javascript">
1421 * @class Roo.bootstrap.MenuMgr
1422 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1425 Roo.bootstrap.MenuMgr = function(){
1426 var menus, active, groups = {}, attached = false, lastShow = new Date();
1428 // private - called when first menu is created
1431 active = new Roo.util.MixedCollection();
1432 Roo.get(document).addKeyListener(27, function(){
1433 if(active.length > 0){
1441 if(active && active.length > 0){
1442 var c = active.clone();
1452 if(active.length < 1){
1453 Roo.get(document).un("mouseup", onMouseDown);
1461 var last = active.last();
1462 lastShow = new Date();
1465 Roo.get(document).on("mouseup", onMouseDown);
1470 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1471 m.parentMenu.activeChild = m;
1472 }else if(last && last.isVisible()){
1473 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1478 function onBeforeHide(m){
1480 m.activeChild.hide();
1482 if(m.autoHideTimer){
1483 clearTimeout(m.autoHideTimer);
1484 delete m.autoHideTimer;
1489 function onBeforeShow(m){
1490 var pm = m.parentMenu;
1491 if(!pm && !m.allowOtherMenus){
1493 }else if(pm && pm.activeChild && active != m){
1494 pm.activeChild.hide();
1499 function onMouseDown(e){
1500 Roo.log("on MouseDown");
1501 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1509 function onBeforeCheck(mi, state){
1511 var g = groups[mi.group];
1512 for(var i = 0, l = g.length; i < l; i++){
1514 g[i].setChecked(false);
1523 * Hides all menus that are currently visible
1525 hideAll : function(){
1530 register : function(menu){
1534 menus[menu.id] = menu;
1535 menu.on("beforehide", onBeforeHide);
1536 menu.on("hide", onHide);
1537 menu.on("beforeshow", onBeforeShow);
1538 menu.on("show", onShow);
1540 if(g && menu.events["checkchange"]){
1544 groups[g].push(menu);
1545 menu.on("checkchange", onCheck);
1550 * Returns a {@link Roo.menu.Menu} object
1551 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1552 * be used to generate and return a new Menu instance.
1554 get : function(menu){
1555 if(typeof menu == "string"){ // menu id
1557 }else if(menu.events){ // menu instance
1560 /*else if(typeof menu.length == 'number'){ // array of menu items?
1561 return new Roo.bootstrap.Menu({items:menu});
1562 }else{ // otherwise, must be a config
1563 return new Roo.bootstrap.Menu(menu);
1570 unregister : function(menu){
1571 delete menus[menu.id];
1572 menu.un("beforehide", onBeforeHide);
1573 menu.un("hide", onHide);
1574 menu.un("beforeshow", onBeforeShow);
1575 menu.un("show", onShow);
1577 if(g && menu.events["checkchange"]){
1578 groups[g].remove(menu);
1579 menu.un("checkchange", onCheck);
1584 registerCheckable : function(menuItem){
1585 var g = menuItem.group;
1590 groups[g].push(menuItem);
1591 menuItem.on("beforecheckchange", onBeforeCheck);
1596 unregisterCheckable : function(menuItem){
1597 var g = menuItem.group;
1599 groups[g].remove(menuItem);
1600 menuItem.un("beforecheckchange", onBeforeCheck);
1612 * @class Roo.bootstrap.Menu
1613 * @extends Roo.bootstrap.Component
1614 * Bootstrap Menu class - container for MenuItems
1615 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1619 * @param {Object} config The config object
1623 Roo.bootstrap.Menu = function(config){
1624 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1625 if (this.registerMenu) {
1626 Roo.bootstrap.MenuMgr.register(this);
1631 * Fires before this menu is displayed
1632 * @param {Roo.menu.Menu} this
1637 * Fires before this menu is hidden
1638 * @param {Roo.menu.Menu} this
1643 * Fires after this menu is displayed
1644 * @param {Roo.menu.Menu} this
1649 * Fires after this menu is hidden
1650 * @param {Roo.menu.Menu} this
1655 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1656 * @param {Roo.menu.Menu} this
1657 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658 * @param {Roo.EventObject} e
1663 * Fires when the mouse is hovering over this menu
1664 * @param {Roo.menu.Menu} this
1665 * @param {Roo.EventObject} e
1666 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1671 * Fires when the mouse exits this menu
1672 * @param {Roo.menu.Menu} this
1673 * @param {Roo.EventObject} e
1674 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1679 * Fires when a menu item contained in this menu is clicked
1680 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1681 * @param {Roo.EventObject} e
1685 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1688 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1692 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1695 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1697 registerMenu : true,
1699 menuItems :false, // stores the menu items..
1705 getChildContainer : function() {
1709 getAutoCreate : function(){
1711 //if (['right'].indexOf(this.align)!==-1) {
1712 // cfg.cn[1].cls += ' pull-right'
1718 cls : 'dropdown-menu' ,
1719 style : 'z-index:1000'
1723 if (this.type === 'submenu') {
1724 cfg.cls = 'submenu active';
1726 if (this.type === 'treeview') {
1727 cfg.cls = 'treeview-menu';
1732 initEvents : function() {
1734 // Roo.log("ADD event");
1735 // Roo.log(this.triggerEl.dom);
1736 this.triggerEl.on('click', this.onTriggerPress, this);
1737 this.triggerEl.addClass('dropdown-toggle');
1738 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1740 this.el.on("mouseover", this.onMouseOver, this);
1741 this.el.on("mouseout", this.onMouseOut, this);
1745 findTargetItem : function(e){
1746 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1750 //Roo.log(t); Roo.log(t.id);
1752 //Roo.log(this.menuitems);
1753 return this.menuitems.get(t.id);
1755 //return this.items.get(t.menuItemId);
1760 onClick : function(e){
1761 Roo.log("menu.onClick");
1762 var t = this.findTargetItem(e);
1763 if(!t || t.isContainer){
1768 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1769 if(t == this.activeItem && t.shouldDeactivate(e)){
1770 this.activeItem.deactivate();
1771 delete this.activeItem;
1775 this.setActiveItem(t, true);
1783 Roo.log('pass click event');
1787 this.fireEvent("click", this, t, e);
1791 onMouseOver : function(e){
1792 var t = this.findTargetItem(e);
1795 // if(t.canActivate && !t.disabled){
1796 // this.setActiveItem(t, true);
1800 this.fireEvent("mouseover", this, e, t);
1802 isVisible : function(){
1803 return !this.hidden;
1805 onMouseOut : function(e){
1806 var t = this.findTargetItem(e);
1809 // if(t == this.activeItem && t.shouldDeactivate(e)){
1810 // this.activeItem.deactivate();
1811 // delete this.activeItem;
1814 this.fireEvent("mouseout", this, e, t);
1819 * Displays this menu relative to another element
1820 * @param {String/HTMLElement/Roo.Element} element The element to align to
1821 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1822 * the element (defaults to this.defaultAlign)
1823 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1825 show : function(el, pos, parentMenu){
1826 this.parentMenu = parentMenu;
1830 this.fireEvent("beforeshow", this);
1831 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1834 * Displays this menu at a specific xy position
1835 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1836 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1838 showAt : function(xy, parentMenu, /* private: */_e){
1839 this.parentMenu = parentMenu;
1844 this.fireEvent("beforeshow", this);
1846 //xy = this.el.adjustForConstraints(xy);
1848 //this.el.setXY(xy);
1850 this.hideMenuItems();
1851 this.hidden = false;
1852 this.triggerEl.addClass('open');
1854 this.fireEvent("show", this);
1860 this.doFocus.defer(50, this);
1864 doFocus : function(){
1866 this.focusEl.focus();
1871 * Hides this menu and optionally all parent menus
1872 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1874 hide : function(deep){
1876 this.hideMenuItems();
1877 if(this.el && this.isVisible()){
1878 this.fireEvent("beforehide", this);
1879 if(this.activeItem){
1880 this.activeItem.deactivate();
1881 this.activeItem = null;
1883 this.triggerEl.removeClass('open');;
1885 this.fireEvent("hide", this);
1887 if(deep === true && this.parentMenu){
1888 this.parentMenu.hide(true);
1892 onTriggerPress : function(e)
1895 Roo.log('trigger press');
1896 //Roo.log(e.getTarget());
1897 // Roo.log(this.triggerEl.dom);
1898 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1901 if (this.isVisible()) {
1905 this.show(this.triggerEl, false, false);
1914 hideMenuItems : function()
1916 //$(backdrop).remove()
1917 Roo.select('.open',true).each(function(aa) {
1919 aa.removeClass('open');
1920 //var parent = getParent($(this))
1921 //var relatedTarget = { relatedTarget: this }
1923 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1924 //if (e.isDefaultPrevented()) return
1925 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1928 addxtypeChild : function (tree, cntr) {
1929 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1931 this.menuitems.add(comp);
1952 * @class Roo.bootstrap.MenuItem
1953 * @extends Roo.bootstrap.Component
1954 * Bootstrap MenuItem class
1955 * @cfg {String} html the menu label
1956 * @cfg {String} href the link
1957 * @cfg {Boolean} preventDefault (true | false) default true
1958 * @cfg {Boolean} isContainer (true | false) default false
1962 * Create a new MenuItem
1963 * @param {Object} config The config object
1967 Roo.bootstrap.MenuItem = function(config){
1968 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1973 * The raw click event for the entire grid.
1974 * @param {Roo.bootstrap.MenuItem} this
1975 * @param {Roo.EventObject} e
1981 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1985 preventDefault: true,
1986 isContainer : false,
1988 getAutoCreate : function(){
1990 if(this.isContainer){
1993 cls: 'dropdown-menu-item'
1999 cls: 'dropdown-menu-item',
2008 if (this.parent().type == 'treeview') {
2009 cfg.cls = 'treeview-menu';
2012 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2013 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2017 initEvents: function() {
2019 //this.el.select('a').on('click', this.onClick, this);
2022 onClick : function(e)
2024 Roo.log('item on click ');
2025 //if(this.preventDefault){
2026 // e.preventDefault();
2028 //this.parent().hideMenuItems();
2030 this.fireEvent('click', this, e);
2049 * @class Roo.bootstrap.MenuSeparator
2050 * @extends Roo.bootstrap.Component
2051 * Bootstrap MenuSeparator class
2054 * Create a new MenuItem
2055 * @param {Object} config The config object
2059 Roo.bootstrap.MenuSeparator = function(config){
2060 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2063 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2065 getAutoCreate : function(){
2084 * @class Roo.bootstrap.Modal
2085 * @extends Roo.bootstrap.Component
2086 * Bootstrap Modal class
2087 * @cfg {String} title Title of dialog
2088 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2089 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2090 * @cfg {Boolean} specificTitle default false
2091 * @cfg {Array} buttons Array of buttons or standard button set..
2092 * @cfg {String} buttonPosition (left|right|center) default right
2093 * @cfg {Boolean} animate default true
2094 * @cfg {Boolean} allow_close default true
2097 * Create a new Modal Dialog
2098 * @param {Object} config The config object
2101 Roo.bootstrap.Modal = function(config){
2102 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2107 * The raw btnclick event for the button
2108 * @param {Roo.EventObject} e
2112 this.buttons = this.buttons || [];
2115 this.tmpl = Roo.factory(this.tmpl);
2120 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2122 title : 'test dialog',
2132 specificTitle: false,
2134 buttonPosition: 'right',
2148 onRender : function(ct, position)
2150 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2153 var cfg = Roo.apply({}, this.getAutoCreate());
2156 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2158 //if (!cfg.name.length) {
2162 cfg.cls += ' ' + this.cls;
2165 cfg.style = this.style;
2167 this.el = Roo.get(document.body).createChild(cfg, position);
2169 //var type = this.el.dom.type;
2174 if(this.tabIndex !== undefined){
2175 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2179 this.bodyEl = this.el.select('.modal-body',true).first();
2180 this.closeEl = this.el.select('.modal-header .close', true).first();
2181 this.footerEl = this.el.select('.modal-footer',true).first();
2182 this.titleEl = this.el.select('.modal-title',true).first();
2186 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2187 this.maskEl.enableDisplayMode("block");
2189 //this.el.addClass("x-dlg-modal");
2191 if (this.buttons.length) {
2192 Roo.each(this.buttons, function(bb) {
2193 b = Roo.apply({}, bb);
2194 b.xns = b.xns || Roo.bootstrap;
2195 b.xtype = b.xtype || 'Button';
2196 if (typeof(b.listeners) == 'undefined') {
2197 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2200 var btn = Roo.factory(b);
2202 btn.onRender(this.el.select('.modal-footer div').first());
2206 // render the children.
2209 if(typeof(this.items) != 'undefined'){
2210 var items = this.items;
2213 for(var i =0;i < items.length;i++) {
2214 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2218 this.items = nitems;
2220 // where are these used - they used to be body/close/footer
2224 //this.el.addClass([this.fieldClass, this.cls]);
2227 getAutoCreate : function(){
2232 html : this.html || ''
2237 cls : 'modal-title',
2241 if(this.specificTitle){
2247 if (this.allow_close) {
2258 style : 'display: none',
2261 cls: "modal-dialog",
2264 cls : "modal-content",
2267 cls : 'modal-header',
2272 cls : 'modal-footer',
2276 cls: 'btn-' + this.buttonPosition
2293 modal.cls += ' fade';
2299 getChildContainer : function() {
2304 getButtonContainer : function() {
2305 return this.el.select('.modal-footer div',true).first();
2308 initEvents : function()
2310 if (this.allow_close) {
2311 this.closeEl.on('click', this.hide, this);
2317 if (!this.rendered) {
2321 this.el.setStyle('display', 'block');
2325 (function(){ _this.el.addClass('in'); }).defer(50);
2327 this.el.addClass('in');
2330 // not sure how we can show data in here..
2332 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2335 Roo.get(document.body).addClass("x-body-masked");
2336 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2338 this.el.setStyle('zIndex', '10001');
2340 this.fireEvent('show', this);
2347 Roo.get(document.body).removeClass("x-body-masked");
2348 this.el.removeClass('in');
2352 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2354 this.el.setStyle('display', 'none');
2357 this.fireEvent('hide', this);
2360 addButton : function(str, cb)
2364 var b = Roo.apply({}, { html : str } );
2365 b.xns = b.xns || Roo.bootstrap;
2366 b.xtype = b.xtype || 'Button';
2367 if (typeof(b.listeners) == 'undefined') {
2368 b.listeners = { click : cb.createDelegate(this) };
2371 var btn = Roo.factory(b);
2373 btn.onRender(this.el.select('.modal-footer div').first());
2379 setDefaultButton : function(btn)
2381 //this.el.select('.modal-footer').()
2383 resizeTo: function(w,h)
2387 setContentSize : function(w, h)
2391 onButtonClick: function(btn,e)
2394 this.fireEvent('btnclick', btn.name, e);
2397 * Set the title of the Dialog
2398 * @param {String} str new Title
2400 setTitle: function(str) {
2401 this.titleEl.dom.innerHTML = str;
2404 * Set the body of the Dialog
2405 * @param {String} str new Title
2407 setBody: function(str) {
2408 this.bodyEl.dom.innerHTML = str;
2411 * Set the body of the Dialog using the template
2412 * @param {Obj} data - apply this data to the template and replace the body contents.
2414 applyBody: function(obj)
2417 Roo.log("Error - using apply Body without a template");
2420 this.tmpl.overwrite(this.bodyEl, obj);
2426 Roo.apply(Roo.bootstrap.Modal, {
2428 * Button config that displays a single OK button
2437 * Button config that displays Yes and No buttons
2453 * Button config that displays OK and Cancel buttons
2468 * Button config that displays Yes, No and Cancel buttons
2491 * messagebox - can be used as a replace
2495 * @class Roo.MessageBox
2496 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2500 Roo.Msg.alert('Status', 'Changes saved successfully.');
2502 // Prompt for user data:
2503 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2505 // process text value...
2509 // Show a dialog using config options:
2511 title:'Save Changes?',
2512 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2513 buttons: Roo.Msg.YESNOCANCEL,
2520 Roo.bootstrap.MessageBox = function(){
2521 var dlg, opt, mask, waitTimer;
2522 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2523 var buttons, activeTextEl, bwidth;
2527 var handleButton = function(button){
2529 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2533 var handleHide = function(){
2535 dlg.el.removeClass(opt.cls);
2538 // Roo.TaskMgr.stop(waitTimer);
2539 // waitTimer = null;
2544 var updateButtons = function(b){
2547 buttons["ok"].hide();
2548 buttons["cancel"].hide();
2549 buttons["yes"].hide();
2550 buttons["no"].hide();
2551 //dlg.footer.dom.style.display = 'none';
2554 dlg.footerEl.dom.style.display = '';
2555 for(var k in buttons){
2556 if(typeof buttons[k] != "function"){
2559 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2560 width += buttons[k].el.getWidth()+15;
2570 var handleEsc = function(d, k, e){
2571 if(opt && opt.closable !== false){
2581 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2582 * @return {Roo.BasicDialog} The BasicDialog element
2584 getDialog : function(){
2586 dlg = new Roo.bootstrap.Modal( {
2589 //constraintoviewport:false,
2591 //collapsible : false,
2596 //buttonAlign:"center",
2597 closeClick : function(){
2598 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2601 handleButton("cancel");
2606 dlg.on("hide", handleHide);
2608 //dlg.addKeyListener(27, handleEsc);
2610 this.buttons = buttons;
2611 var bt = this.buttonText;
2612 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2613 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2614 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2615 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2617 bodyEl = dlg.bodyEl.createChild({
2619 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2620 '<textarea class="roo-mb-textarea"></textarea>' +
2621 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2623 msgEl = bodyEl.dom.firstChild;
2624 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2625 textboxEl.enableDisplayMode();
2626 textboxEl.addKeyListener([10,13], function(){
2627 if(dlg.isVisible() && opt && opt.buttons){
2630 }else if(opt.buttons.yes){
2631 handleButton("yes");
2635 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2636 textareaEl.enableDisplayMode();
2637 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2638 progressEl.enableDisplayMode();
2639 var pf = progressEl.dom.firstChild;
2641 pp = Roo.get(pf.firstChild);
2642 pp.setHeight(pf.offsetHeight);
2650 * Updates the message box body text
2651 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2652 * the XHTML-compliant non-breaking space character '&#160;')
2653 * @return {Roo.MessageBox} This message box
2655 updateText : function(text){
2656 if(!dlg.isVisible() && !opt.width){
2657 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2659 msgEl.innerHTML = text || ' ';
2661 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2662 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2664 Math.min(opt.width || cw , this.maxWidth),
2665 Math.max(opt.minWidth || this.minWidth, bwidth)
2668 activeTextEl.setWidth(w);
2670 if(dlg.isVisible()){
2671 dlg.fixedcenter = false;
2673 // to big, make it scroll. = But as usual stupid IE does not support
2676 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2677 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2678 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2680 bodyEl.dom.style.height = '';
2681 bodyEl.dom.style.overflowY = '';
2684 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2686 bodyEl.dom.style.overflowX = '';
2689 dlg.setContentSize(w, bodyEl.getHeight());
2690 if(dlg.isVisible()){
2691 dlg.fixedcenter = true;
2697 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2698 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2699 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2700 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2701 * @return {Roo.MessageBox} This message box
2703 updateProgress : function(value, text){
2705 this.updateText(text);
2707 if (pp) { // weird bug on my firefox - for some reason this is not defined
2708 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2714 * Returns true if the message box is currently displayed
2715 * @return {Boolean} True if the message box is visible, else false
2717 isVisible : function(){
2718 return dlg && dlg.isVisible();
2722 * Hides the message box if it is displayed
2725 if(this.isVisible()){
2731 * Displays a new message box, or reinitializes an existing message box, based on the config options
2732 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2733 * The following config object properties are supported:
2735 Property Type Description
2736 ---------- --------------- ------------------------------------------------------------------------------------
2737 animEl String/Element An id or Element from which the message box should animate as it opens and
2738 closes (defaults to undefined)
2739 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2740 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2741 closable Boolean False to hide the top-right close button (defaults to true). Note that
2742 progress and wait dialogs will ignore this property and always hide the
2743 close button as they can only be closed programmatically.
2744 cls String A custom CSS class to apply to the message box element
2745 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2746 displayed (defaults to 75)
2747 fn Function A callback function to execute after closing the dialog. The arguments to the
2748 function will be btn (the name of the button that was clicked, if applicable,
2749 e.g. "ok"), and text (the value of the active text field, if applicable).
2750 Progress and wait dialogs will ignore this option since they do not respond to
2751 user actions and can only be closed programmatically, so any required function
2752 should be called by the same code after it closes the dialog.
2753 icon String A CSS class that provides a background image to be used as an icon for
2754 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2755 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2756 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2757 modal Boolean False to allow user interaction with the page while the message box is
2758 displayed (defaults to true)
2759 msg String A string that will replace the existing message box body text (defaults
2760 to the XHTML-compliant non-breaking space character ' ')
2761 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2762 progress Boolean True to display a progress bar (defaults to false)
2763 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2764 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2765 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2766 title String The title text
2767 value String The string value to set into the active textbox element if displayed
2768 wait Boolean True to display a progress bar (defaults to false)
2769 width Number The width of the dialog in pixels
2776 msg: 'Please enter your address:',
2778 buttons: Roo.MessageBox.OKCANCEL,
2781 animEl: 'addAddressBtn'
2784 * @param {Object} config Configuration options
2785 * @return {Roo.MessageBox} This message box
2787 show : function(options)
2790 // this causes nightmares if you show one dialog after another
2791 // especially on callbacks..
2793 if(this.isVisible()){
2796 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2797 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2798 Roo.log("New Dialog Message:" + options.msg )
2799 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2800 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2803 var d = this.getDialog();
2805 d.setTitle(opt.title || " ");
2806 d.closeEl.setDisplayed(opt.closable !== false);
2807 activeTextEl = textboxEl;
2808 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2813 textareaEl.setHeight(typeof opt.multiline == "number" ?
2814 opt.multiline : this.defaultTextHeight);
2815 activeTextEl = textareaEl;
2824 progressEl.setDisplayed(opt.progress === true);
2825 this.updateProgress(0);
2826 activeTextEl.dom.value = opt.value || "";
2828 dlg.setDefaultButton(activeTextEl);
2830 var bs = opt.buttons;
2834 }else if(bs && bs.yes){
2835 db = buttons["yes"];
2837 dlg.setDefaultButton(db);
2839 bwidth = updateButtons(opt.buttons);
2840 this.updateText(opt.msg);
2842 d.el.addClass(opt.cls);
2844 d.proxyDrag = opt.proxyDrag === true;
2845 d.modal = opt.modal !== false;
2846 d.mask = opt.modal !== false ? mask : false;
2848 // force it to the end of the z-index stack so it gets a cursor in FF
2849 document.body.appendChild(dlg.el.dom);
2850 d.animateTarget = null;
2851 d.show(options.animEl);
2857 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2858 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2859 * and closing the message box when the process is complete.
2860 * @param {String} title The title bar text
2861 * @param {String} msg The message box body text
2862 * @return {Roo.MessageBox} This message box
2864 progress : function(title, msg){
2871 minWidth: this.minProgressWidth,
2878 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2879 * If a callback function is passed it will be called after the user clicks the button, and the
2880 * id of the button that was clicked will be passed as the only parameter to the callback
2881 * (could also be the top-right close button).
2882 * @param {String} title The title bar text
2883 * @param {String} msg The message box body text
2884 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2885 * @param {Object} scope (optional) The scope of the callback function
2886 * @return {Roo.MessageBox} This message box
2888 alert : function(title, msg, fn, scope){
2901 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2902 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2903 * You are responsible for closing the message box when the process is complete.
2904 * @param {String} msg The message box body text
2905 * @param {String} title (optional) The title bar text
2906 * @return {Roo.MessageBox} This message box
2908 wait : function(msg, title){
2919 waitTimer = Roo.TaskMgr.start({
2921 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2929 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2930 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2931 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2932 * @param {String} title The title bar text
2933 * @param {String} msg The message box body text
2934 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2935 * @param {Object} scope (optional) The scope of the callback function
2936 * @return {Roo.MessageBox} This message box
2938 confirm : function(title, msg, fn, scope){
2942 buttons: this.YESNO,
2951 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2952 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2953 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2954 * (could also be the top-right close button) and the text that was entered will be passed as the two
2955 * parameters to the callback.
2956 * @param {String} title The title bar text
2957 * @param {String} msg The message box body text
2958 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2959 * @param {Object} scope (optional) The scope of the callback function
2960 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2961 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2962 * @return {Roo.MessageBox} This message box
2964 prompt : function(title, msg, fn, scope, multiline){
2968 buttons: this.OKCANCEL,
2973 multiline: multiline,
2980 * Button config that displays a single OK button
2985 * Button config that displays Yes and No buttons
2988 YESNO : {yes:true, no:true},
2990 * Button config that displays OK and Cancel buttons
2993 OKCANCEL : {ok:true, cancel:true},
2995 * Button config that displays Yes, No and Cancel buttons
2998 YESNOCANCEL : {yes:true, no:true, cancel:true},
3001 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3004 defaultTextHeight : 75,
3006 * The maximum width in pixels of the message box (defaults to 600)
3011 * The minimum width in pixels of the message box (defaults to 100)
3016 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3017 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3020 minProgressWidth : 250,
3022 * An object containing the default button text strings that can be overriden for localized language support.
3023 * Supported properties are: ok, cancel, yes and no.
3024 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3037 * Shorthand for {@link Roo.MessageBox}
3039 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3040 Roo.Msg = Roo.Msg || Roo.MessageBox;
3049 * @class Roo.bootstrap.Navbar
3050 * @extends Roo.bootstrap.Component
3051 * Bootstrap Navbar class
3054 * Create a new Navbar
3055 * @param {Object} config The config object
3059 Roo.bootstrap.Navbar = function(config){
3060 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3064 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3073 getAutoCreate : function(){
3076 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3080 initEvents :function ()
3082 //Roo.log(this.el.select('.navbar-toggle',true));
3083 this.el.select('.navbar-toggle',true).on('click', function() {
3084 // Roo.log('click');
3085 this.el.select('.navbar-collapse',true).toggleClass('in');
3093 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3095 var size = this.el.getSize();
3096 this.maskEl.setSize(size.width, size.height);
3097 this.maskEl.enableDisplayMode("block");
3106 getChildContainer : function()
3108 if (this.el.select('.collapse').getCount()) {
3109 return this.el.select('.collapse',true).first();
3142 * @class Roo.bootstrap.NavSimplebar
3143 * @extends Roo.bootstrap.Navbar
3144 * Bootstrap Sidebar class
3146 * @cfg {Boolean} inverse is inverted color
3148 * @cfg {String} type (nav | pills | tabs)
3149 * @cfg {Boolean} arrangement stacked | justified
3150 * @cfg {String} align (left | right) alignment
3152 * @cfg {Boolean} main (true|false) main nav bar? default false
3153 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3155 * @cfg {String} tag (header|footer|nav|div) default is nav
3161 * Create a new Sidebar
3162 * @param {Object} config The config object
3166 Roo.bootstrap.NavSimplebar = function(config){
3167 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3170 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3186 getAutoCreate : function(){
3190 tag : this.tag || 'div',
3203 this.type = this.type || 'nav';
3204 if (['tabs','pills'].indexOf(this.type)!==-1) {
3205 cfg.cn[0].cls += ' nav-' + this.type
3209 if (this.type!=='nav') {
3210 Roo.log('nav type must be nav/tabs/pills')
3212 cfg.cn[0].cls += ' navbar-nav'
3218 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3219 cfg.cn[0].cls += ' nav-' + this.arrangement;
3223 if (this.align === 'right') {
3224 cfg.cn[0].cls += ' navbar-right';
3228 cfg.cls += ' navbar-inverse';
3255 * @class Roo.bootstrap.NavHeaderbar
3256 * @extends Roo.bootstrap.NavSimplebar
3257 * Bootstrap Sidebar class
3259 * @cfg {String} brand what is brand
3260 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3261 * @cfg {String} brand_href href of the brand
3262 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3263 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3264 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3265 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3268 * Create a new Sidebar
3269 * @param {Object} config The config object
3273 Roo.bootstrap.NavHeaderbar = function(config){
3274 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3278 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3285 desktopCenter : false,
3288 getAutoCreate : function(){
3291 tag: this.nav || 'nav',
3298 if (this.desktopCenter) {
3299 cn.push({cls : 'container', cn : []});
3306 cls: 'navbar-header',
3311 cls: 'navbar-toggle',
3312 'data-toggle': 'collapse',
3317 html: 'Toggle navigation'
3339 cls: 'collapse navbar-collapse',
3343 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3345 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3346 cfg.cls += ' navbar-' + this.position;
3348 // tag can override this..
3350 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3353 if (this.brand !== '') {
3356 href: this.brand_href ? this.brand_href : '#',
3357 cls: 'navbar-brand',
3365 cfg.cls += ' main-nav';
3373 getHeaderChildContainer : function()
3375 if (this.el.select('.navbar-header').getCount()) {
3376 return this.el.select('.navbar-header',true).first();
3379 return this.getChildContainer();
3383 initEvents : function()
3385 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3387 if (this.autohide) {
3392 Roo.get(document).on('scroll',function(e) {
3393 var ns = Roo.get(document).getScroll().top;
3394 var os = prevScroll;
3398 ft.removeClass('slideDown');
3399 ft.addClass('slideUp');
3402 ft.removeClass('slideUp');
3403 ft.addClass('slideDown');
3427 * @class Roo.bootstrap.NavSidebar
3428 * @extends Roo.bootstrap.Navbar
3429 * Bootstrap Sidebar class
3432 * Create a new Sidebar
3433 * @param {Object} config The config object
3437 Roo.bootstrap.NavSidebar = function(config){
3438 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3441 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3443 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3445 getAutoCreate : function(){
3450 cls: 'sidebar sidebar-nav'
3472 * @class Roo.bootstrap.NavGroup
3473 * @extends Roo.bootstrap.Component
3474 * Bootstrap NavGroup class
3475 * @cfg {String} align left | right
3476 * @cfg {Boolean} inverse false | true
3477 * @cfg {String} type (nav|pills|tab) default nav
3478 * @cfg {String} navId - reference Id for navbar.
3482 * Create a new nav group
3483 * @param {Object} config The config object
3486 Roo.bootstrap.NavGroup = function(config){
3487 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3490 Roo.bootstrap.NavGroup.register(this);
3494 * Fires when the active item changes
3495 * @param {Roo.bootstrap.NavGroup} this
3496 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3497 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3504 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3515 getAutoCreate : function()
3517 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3524 if (['tabs','pills'].indexOf(this.type)!==-1) {
3525 cfg.cls += ' nav-' + this.type
3527 if (this.type!=='nav') {
3528 Roo.log('nav type must be nav/tabs/pills')
3530 cfg.cls += ' navbar-nav'
3533 if (this.parent().sidebar) {
3536 cls: 'dashboard-menu sidebar-menu'
3542 if (this.form === true) {
3548 if (this.align === 'right') {
3549 cfg.cls += ' navbar-right';
3551 cfg.cls += ' navbar-left';
3555 if (this.align === 'right') {
3556 cfg.cls += ' navbar-right';
3560 cfg.cls += ' navbar-inverse';
3568 * sets the active Navigation item
3569 * @param {Roo.bootstrap.NavItem} the new current navitem
3571 setActiveItem : function(item)
3574 Roo.each(this.navItems, function(v){
3579 v.setActive(false, true);
3586 item.setActive(true, true);
3587 this.fireEvent('changed', this, item, prev);
3592 * gets the active Navigation item
3593 * @return {Roo.bootstrap.NavItem} the current navitem
3595 getActive : function()
3599 Roo.each(this.navItems, function(v){
3610 indexOfNav : function()
3614 Roo.each(this.navItems, function(v,i){
3625 * adds a Navigation item
3626 * @param {Roo.bootstrap.NavItem} the navitem to add
3628 addItem : function(cfg)
3630 var cn = new Roo.bootstrap.NavItem(cfg);
3632 cn.parentId = this.id;
3633 cn.onRender(this.el, null);
3637 * register a Navigation item
3638 * @param {Roo.bootstrap.NavItem} the navitem to add
3640 register : function(item)
3642 this.navItems.push( item);
3643 item.navId = this.navId;
3648 * clear all the Navigation item
3651 clearAll : function()
3654 this.el.dom.innerHTML = '';
3657 getNavItem: function(tabId)
3660 Roo.each(this.navItems, function(e) {
3661 if (e.tabId == tabId) {
3671 setActiveNext : function()
3673 var i = this.indexOfNav(this.getActive());
3674 if (i > this.navItems.length) {
3677 this.setActiveItem(this.navItems[i+1]);
3679 setActivePrev : function()
3681 var i = this.indexOfNav(this.getActive());
3685 this.setActiveItem(this.navItems[i-1]);
3687 clearWasActive : function(except) {
3688 Roo.each(this.navItems, function(e) {
3689 if (e.tabId != except.tabId && e.was_active) {
3690 e.was_active = false;
3697 getWasActive : function ()
3700 Roo.each(this.navItems, function(e) {
3715 Roo.apply(Roo.bootstrap.NavGroup, {
3719 * register a Navigation Group
3720 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3722 register : function(navgrp)
3724 this.groups[navgrp.navId] = navgrp;
3728 * fetch a Navigation Group based on the navigation ID
3729 * @param {string} the navgroup to add
3730 * @returns {Roo.bootstrap.NavGroup} the navgroup
3732 get: function(navId) {
3733 if (typeof(this.groups[navId]) == 'undefined') {
3735 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3737 return this.groups[navId] ;
3752 * @class Roo.bootstrap.NavItem
3753 * @extends Roo.bootstrap.Component
3754 * Bootstrap Navbar.NavItem class
3755 * @cfg {String} href link to
3756 * @cfg {String} html content of button
3757 * @cfg {String} badge text inside badge
3758 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3759 * @cfg {String} glyphicon name of glyphicon
3760 * @cfg {String} icon name of font awesome icon
3761 * @cfg {Boolean} active Is item active
3762 * @cfg {Boolean} disabled Is item disabled
3764 * @cfg {Boolean} preventDefault (true | false) default false
3765 * @cfg {String} tabId the tab that this item activates.
3766 * @cfg {String} tagtype (a|span) render as a href or span?
3767 * @cfg {Boolean} animateRef (true|false) link to element default false
3770 * Create a new Navbar Item
3771 * @param {Object} config The config object
3773 Roo.bootstrap.NavItem = function(config){
3774 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3779 * The raw click event for the entire grid.
3780 * @param {Roo.EventObject} e
3785 * Fires when the active item active state changes
3786 * @param {Roo.bootstrap.NavItem} this
3787 * @param {boolean} state the new state
3793 * Fires when scroll to element
3794 * @param {Roo.bootstrap.NavItem} this
3795 * @param {Object} options
3796 * @param {Roo.EventObject} e
3804 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3812 preventDefault : false,
3819 getAutoCreate : function(){
3827 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3829 if (this.disabled) {
3830 cfg.cls += ' disabled';
3833 if (this.href || this.html || this.glyphicon || this.icon) {
3837 href : this.href || "#",
3838 html: this.html || ''
3843 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3846 if(this.glyphicon) {
3847 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3852 cfg.cn[0].html += " <span class='caret'></span>";
3856 if (this.badge !== '') {
3858 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3866 initEvents: function()
3868 if (typeof (this.menu) != 'undefined') {
3869 this.menu.parentType = this.xtype;
3870 this.menu.triggerEl = this.el;
3871 this.menu = this.addxtype(Roo.apply({}, this.menu));
3874 this.el.select('a',true).on('click', this.onClick, this);
3876 if(this.tagtype == 'span'){
3877 this.el.select('span',true).on('click', this.onClick, this);
3880 // at this point parent should be available..
3881 this.parent().register(this);
3884 onClick : function(e)
3887 this.preventDefault ||
3889 (this.animateRef && this.href.charAt(0) == '#')
3894 if (this.disabled) {
3898 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3899 if (tg && tg.transition) {
3900 Roo.log("waiting for the transitionend");
3904 Roo.log("fire event clicked");
3905 if(this.fireEvent('click', this, e) === false){
3909 if(this.tagtype == 'span'){
3913 if(this.animateRef && this.href.charAt(0) == '#'){
3914 this.scrollToElement(e);
3918 var p = this.parent();
3919 if (['tabs','pills'].indexOf(p.type)!==-1) {
3920 if (typeof(p.setActiveItem) !== 'undefined') {
3921 p.setActiveItem(this);
3924 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3925 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3926 // remove the collapsed menu expand...
3927 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3932 isActive: function () {
3935 setActive : function(state, fire, is_was_active)
3937 if (this.active && !state & this.navId) {
3938 this.was_active = true;
3939 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3941 nv.clearWasActive(this);
3945 this.active = state;
3948 this.el.removeClass('active');
3949 } else if (!this.el.hasClass('active')) {
3950 this.el.addClass('active');
3953 this.fireEvent('changed', this, state);
3956 // show a panel if it's registered and related..
3958 if (!this.navId || !this.tabId || !state || is_was_active) {
3962 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3966 var pan = tg.getPanelByName(this.tabId);
3970 // if we can not flip to new panel - go back to old nav highlight..
3971 if (false == tg.showPanel(pan)) {
3972 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3974 var onav = nv.getWasActive();
3976 onav.setActive(true, false, true);
3985 // this should not be here...
3986 setDisabled : function(state)
3988 this.disabled = state;
3990 this.el.removeClass('disabled');
3991 } else if (!this.el.hasClass('disabled')) {
3992 this.el.addClass('disabled');
3998 * Fetch the element to display the tooltip on.
3999 * @return {Roo.Element} defaults to this.el
4001 tooltipEl : function()
4003 return this.el.select('' + this.tagtype + '', true).first();
4006 scrollToElement : function(e)
4008 var c = document.body;
4010 var target = Roo.get(c).select('a[name=' + this.href.replace('#', '') +']', true).first();
4016 var o = target.calcOffsetsTo(c);
4023 this.fireEvent('scrollto', this, options, e);
4025 Roo.get(c).scrollTo('top', options.value, true);
4038 * <span> icon </span>
4039 * <span> text </span>
4040 * <span>badge </span>
4044 * @class Roo.bootstrap.NavSidebarItem
4045 * @extends Roo.bootstrap.NavItem
4046 * Bootstrap Navbar.NavSidebarItem class
4048 * Create a new Navbar Button
4049 * @param {Object} config The config object
4051 Roo.bootstrap.NavSidebarItem = function(config){
4052 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4057 * The raw click event for the entire grid.
4058 * @param {Roo.EventObject} e
4063 * Fires when the active item active state changes
4064 * @param {Roo.bootstrap.NavSidebarItem} this
4065 * @param {boolean} state the new state
4073 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4076 getAutoCreate : function(){
4081 href : this.href || '#',
4093 html : this.html || ''
4098 cfg.cls += ' active';
4102 if (this.glyphicon || this.icon) {
4103 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4104 a.cn.push({ tag : 'i', cls : c }) ;
4109 if (this.badge !== '') {
4110 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4114 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4115 a.cls += 'dropdown-toggle treeview' ;
4139 * @class Roo.bootstrap.Row
4140 * @extends Roo.bootstrap.Component
4141 * Bootstrap Row class (contains columns...)
4145 * @param {Object} config The config object
4148 Roo.bootstrap.Row = function(config){
4149 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4152 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4154 getAutoCreate : function(){
4173 * @class Roo.bootstrap.Element
4174 * @extends Roo.bootstrap.Component
4175 * Bootstrap Element class
4176 * @cfg {String} html contents of the element
4177 * @cfg {String} tag tag of the element
4178 * @cfg {String} cls class of the element
4181 * Create a new Element
4182 * @param {Object} config The config object
4185 Roo.bootstrap.Element = function(config){
4186 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4189 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4196 getAutoCreate : function(){
4209 getValue : function()
4211 return this.el.dom.innerHTML;
4214 setValue : function(value)
4216 this.el.dom.innerHTML = value;
4231 * @class Roo.bootstrap.Pagination
4232 * @extends Roo.bootstrap.Component
4233 * Bootstrap Pagination class
4234 * @cfg {String} size xs | sm | md | lg
4235 * @cfg {Boolean} inverse false | true
4238 * Create a new Pagination
4239 * @param {Object} config The config object
4242 Roo.bootstrap.Pagination = function(config){
4243 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4246 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4252 getAutoCreate : function(){
4258 cfg.cls += ' inverse';
4264 cfg.cls += " " + this.cls;
4282 * @class Roo.bootstrap.PaginationItem
4283 * @extends Roo.bootstrap.Component
4284 * Bootstrap PaginationItem class
4285 * @cfg {String} html text
4286 * @cfg {String} href the link
4287 * @cfg {Boolean} preventDefault (true | false) default true
4288 * @cfg {Boolean} active (true | false) default false
4289 * @cfg {Boolean} disabled default false
4293 * Create a new PaginationItem
4294 * @param {Object} config The config object
4298 Roo.bootstrap.PaginationItem = function(config){
4299 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4304 * The raw click event for the entire grid.
4305 * @param {Roo.EventObject} e
4311 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4315 preventDefault: true,
4320 getAutoCreate : function(){
4326 href : this.href ? this.href : '#',
4327 html : this.html ? this.html : ''
4337 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4341 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4347 initEvents: function() {
4349 this.el.on('click', this.onClick, this);
4352 onClick : function(e)
4354 Roo.log('PaginationItem on click ');
4355 if(this.preventDefault){
4363 this.fireEvent('click', this, e);
4379 * @class Roo.bootstrap.Slider
4380 * @extends Roo.bootstrap.Component
4381 * Bootstrap Slider class
4384 * Create a new Slider
4385 * @param {Object} config The config object
4388 Roo.bootstrap.Slider = function(config){
4389 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4392 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4394 getAutoCreate : function(){
4398 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4402 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4414 * Ext JS Library 1.1.1
4415 * Copyright(c) 2006-2007, Ext JS, LLC.
4417 * Originally Released Under LGPL - original licence link has changed is not relivant.
4420 * <script type="text/javascript">
4425 * @class Roo.grid.ColumnModel
4426 * @extends Roo.util.Observable
4427 * This is the default implementation of a ColumnModel used by the Grid. It defines
4428 * the columns in the grid.
4431 var colModel = new Roo.grid.ColumnModel([
4432 {header: "Ticker", width: 60, sortable: true, locked: true},
4433 {header: "Company Name", width: 150, sortable: true},
4434 {header: "Market Cap.", width: 100, sortable: true},
4435 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4436 {header: "Employees", width: 100, sortable: true, resizable: false}
4441 * The config options listed for this class are options which may appear in each
4442 * individual column definition.
4443 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4445 * @param {Object} config An Array of column config objects. See this class's
4446 * config objects for details.
4448 Roo.grid.ColumnModel = function(config){
4450 * The config passed into the constructor
4452 this.config = config;
4455 // if no id, create one
4456 // if the column does not have a dataIndex mapping,
4457 // map it to the order it is in the config
4458 for(var i = 0, len = config.length; i < len; i++){
4460 if(typeof c.dataIndex == "undefined"){
4463 if(typeof c.renderer == "string"){
4464 c.renderer = Roo.util.Format[c.renderer];
4466 if(typeof c.id == "undefined"){
4469 if(c.editor && c.editor.xtype){
4470 c.editor = Roo.factory(c.editor, Roo.grid);
4472 if(c.editor && c.editor.isFormField){
4473 c.editor = new Roo.grid.GridEditor(c.editor);
4475 this.lookup[c.id] = c;
4479 * The width of columns which have no width specified (defaults to 100)
4482 this.defaultWidth = 100;
4485 * Default sortable of columns which have no sortable specified (defaults to false)
4488 this.defaultSortable = false;
4492 * @event widthchange
4493 * Fires when the width of a column changes.
4494 * @param {ColumnModel} this
4495 * @param {Number} columnIndex The column index
4496 * @param {Number} newWidth The new width
4498 "widthchange": true,
4500 * @event headerchange
4501 * Fires when the text of a header changes.
4502 * @param {ColumnModel} this
4503 * @param {Number} columnIndex The column index
4504 * @param {Number} newText The new header text
4506 "headerchange": true,
4508 * @event hiddenchange
4509 * Fires when a column is hidden or "unhidden".
4510 * @param {ColumnModel} this
4511 * @param {Number} columnIndex The column index
4512 * @param {Boolean} hidden true if hidden, false otherwise
4514 "hiddenchange": true,
4516 * @event columnmoved
4517 * Fires when a column is moved.
4518 * @param {ColumnModel} this
4519 * @param {Number} oldIndex
4520 * @param {Number} newIndex
4522 "columnmoved" : true,
4524 * @event columlockchange
4525 * Fires when a column's locked state is changed
4526 * @param {ColumnModel} this
4527 * @param {Number} colIndex
4528 * @param {Boolean} locked true if locked
4530 "columnlockchange" : true
4532 Roo.grid.ColumnModel.superclass.constructor.call(this);
4534 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4536 * @cfg {String} header The header text to display in the Grid view.
4539 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4540 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4541 * specified, the column's index is used as an index into the Record's data Array.
4544 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4545 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4548 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4549 * Defaults to the value of the {@link #defaultSortable} property.
4550 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4553 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4556 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4559 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4562 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4565 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4566 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4567 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4568 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4571 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4574 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4577 * @cfg {String} cursor (Optional)
4580 * @cfg {String} tooltip (Optional)
4583 * Returns the id of the column at the specified index.
4584 * @param {Number} index The column index
4585 * @return {String} the id
4587 getColumnId : function(index){
4588 return this.config[index].id;
4592 * Returns the column for a specified id.
4593 * @param {String} id The column id
4594 * @return {Object} the column
4596 getColumnById : function(id){
4597 return this.lookup[id];
4602 * Returns the column for a specified dataIndex.
4603 * @param {String} dataIndex The column dataIndex
4604 * @return {Object|Boolean} the column or false if not found
4606 getColumnByDataIndex: function(dataIndex){
4607 var index = this.findColumnIndex(dataIndex);
4608 return index > -1 ? this.config[index] : false;
4612 * Returns the index for a specified column id.
4613 * @param {String} id The column id
4614 * @return {Number} the index, or -1 if not found
4616 getIndexById : function(id){
4617 for(var i = 0, len = this.config.length; i < len; i++){
4618 if(this.config[i].id == id){
4626 * Returns the index for a specified column dataIndex.
4627 * @param {String} dataIndex The column dataIndex
4628 * @return {Number} the index, or -1 if not found
4631 findColumnIndex : function(dataIndex){
4632 for(var i = 0, len = this.config.length; i < len; i++){
4633 if(this.config[i].dataIndex == dataIndex){
4641 moveColumn : function(oldIndex, newIndex){
4642 var c = this.config[oldIndex];
4643 this.config.splice(oldIndex, 1);
4644 this.config.splice(newIndex, 0, c);
4645 this.dataMap = null;
4646 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4649 isLocked : function(colIndex){
4650 return this.config[colIndex].locked === true;
4653 setLocked : function(colIndex, value, suppressEvent){
4654 if(this.isLocked(colIndex) == value){
4657 this.config[colIndex].locked = value;
4659 this.fireEvent("columnlockchange", this, colIndex, value);
4663 getTotalLockedWidth : function(){
4665 for(var i = 0; i < this.config.length; i++){
4666 if(this.isLocked(i) && !this.isHidden(i)){
4667 this.totalWidth += this.getColumnWidth(i);
4673 getLockedCount : function(){
4674 for(var i = 0, len = this.config.length; i < len; i++){
4675 if(!this.isLocked(i)){
4682 * Returns the number of columns.
4685 getColumnCount : function(visibleOnly){
4686 if(visibleOnly === true){
4688 for(var i = 0, len = this.config.length; i < len; i++){
4689 if(!this.isHidden(i)){
4695 return this.config.length;
4699 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4700 * @param {Function} fn
4701 * @param {Object} scope (optional)
4702 * @return {Array} result
4704 getColumnsBy : function(fn, scope){
4706 for(var i = 0, len = this.config.length; i < len; i++){
4707 var c = this.config[i];
4708 if(fn.call(scope||this, c, i) === true){
4716 * Returns true if the specified column is sortable.
4717 * @param {Number} col The column index
4720 isSortable : function(col){
4721 if(typeof this.config[col].sortable == "undefined"){
4722 return this.defaultSortable;
4724 return this.config[col].sortable;
4728 * Returns the rendering (formatting) function defined for the column.
4729 * @param {Number} col The column index.
4730 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4732 getRenderer : function(col){
4733 if(!this.config[col].renderer){
4734 return Roo.grid.ColumnModel.defaultRenderer;
4736 return this.config[col].renderer;
4740 * Sets the rendering (formatting) function for a column.
4741 * @param {Number} col The column index
4742 * @param {Function} fn The function to use to process the cell's raw data
4743 * to return HTML markup for the grid view. The render function is called with
4744 * the following parameters:<ul>
4745 * <li>Data value.</li>
4746 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4747 * <li>css A CSS style string to apply to the table cell.</li>
4748 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4749 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4750 * <li>Row index</li>
4751 * <li>Column index</li>
4752 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4754 setRenderer : function(col, fn){
4755 this.config[col].renderer = fn;
4759 * Returns the width for the specified column.
4760 * @param {Number} col The column index
4763 getColumnWidth : function(col){
4764 return this.config[col].width * 1 || this.defaultWidth;
4768 * Sets the width for a column.
4769 * @param {Number} col The column index
4770 * @param {Number} width The new width
4772 setColumnWidth : function(col, width, suppressEvent){
4773 this.config[col].width = width;
4774 this.totalWidth = null;
4776 this.fireEvent("widthchange", this, col, width);
4781 * Returns the total width of all columns.
4782 * @param {Boolean} includeHidden True to include hidden column widths
4785 getTotalWidth : function(includeHidden){
4786 if(!this.totalWidth){
4787 this.totalWidth = 0;
4788 for(var i = 0, len = this.config.length; i < len; i++){
4789 if(includeHidden || !this.isHidden(i)){
4790 this.totalWidth += this.getColumnWidth(i);
4794 return this.totalWidth;
4798 * Returns the header for the specified column.
4799 * @param {Number} col The column index
4802 getColumnHeader : function(col){
4803 return this.config[col].header;
4807 * Sets the header for a column.
4808 * @param {Number} col The column index
4809 * @param {String} header The new header
4811 setColumnHeader : function(col, header){
4812 this.config[col].header = header;
4813 this.fireEvent("headerchange", this, col, header);
4817 * Returns the tooltip for the specified column.
4818 * @param {Number} col The column index
4821 getColumnTooltip : function(col){
4822 return this.config[col].tooltip;
4825 * Sets the tooltip for a column.
4826 * @param {Number} col The column index
4827 * @param {String} tooltip The new tooltip
4829 setColumnTooltip : function(col, tooltip){
4830 this.config[col].tooltip = tooltip;
4834 * Returns the dataIndex for the specified column.
4835 * @param {Number} col The column index
4838 getDataIndex : function(col){
4839 return this.config[col].dataIndex;
4843 * Sets the dataIndex for a column.
4844 * @param {Number} col The column index
4845 * @param {Number} dataIndex The new dataIndex
4847 setDataIndex : function(col, dataIndex){
4848 this.config[col].dataIndex = dataIndex;
4854 * Returns true if the cell is editable.
4855 * @param {Number} colIndex The column index
4856 * @param {Number} rowIndex The row index
4859 isCellEditable : function(colIndex, rowIndex){
4860 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4864 * Returns the editor defined for the cell/column.
4865 * return false or null to disable editing.
4866 * @param {Number} colIndex The column index
4867 * @param {Number} rowIndex The row index
4870 getCellEditor : function(colIndex, rowIndex){
4871 return this.config[colIndex].editor;
4875 * Sets if a column is editable.
4876 * @param {Number} col The column index
4877 * @param {Boolean} editable True if the column is editable
4879 setEditable : function(col, editable){
4880 this.config[col].editable = editable;
4885 * Returns true if the column is hidden.
4886 * @param {Number} colIndex The column index
4889 isHidden : function(colIndex){
4890 return this.config[colIndex].hidden;
4895 * Returns true if the column width cannot be changed
4897 isFixed : function(colIndex){
4898 return this.config[colIndex].fixed;
4902 * Returns true if the column can be resized
4905 isResizable : function(colIndex){
4906 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4909 * Sets if a column is hidden.
4910 * @param {Number} colIndex The column index
4911 * @param {Boolean} hidden True if the column is hidden
4913 setHidden : function(colIndex, hidden){
4914 this.config[colIndex].hidden = hidden;
4915 this.totalWidth = null;
4916 this.fireEvent("hiddenchange", this, colIndex, hidden);
4920 * Sets the editor for a column.
4921 * @param {Number} col The column index
4922 * @param {Object} editor The editor object
4924 setEditor : function(col, editor){
4925 this.config[col].editor = editor;
4929 Roo.grid.ColumnModel.defaultRenderer = function(value){
4930 if(typeof value == "string" && value.length < 1){
4936 // Alias for backwards compatibility
4937 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4940 * Ext JS Library 1.1.1
4941 * Copyright(c) 2006-2007, Ext JS, LLC.
4943 * Originally Released Under LGPL - original licence link has changed is not relivant.
4946 * <script type="text/javascript">
4950 * @class Roo.LoadMask
4951 * A simple utility class for generically masking elements while loading data. If the element being masked has
4952 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4953 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4954 * element's UpdateManager load indicator and will be destroyed after the initial load.
4956 * Create a new LoadMask
4957 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4958 * @param {Object} config The config object
4960 Roo.LoadMask = function(el, config){
4961 this.el = Roo.get(el);
4962 Roo.apply(this, config);
4964 this.store.on('beforeload', this.onBeforeLoad, this);
4965 this.store.on('load', this.onLoad, this);
4966 this.store.on('loadexception', this.onLoadException, this);
4967 this.removeMask = false;
4969 var um = this.el.getUpdateManager();
4970 um.showLoadIndicator = false; // disable the default indicator
4971 um.on('beforeupdate', this.onBeforeLoad, this);
4972 um.on('update', this.onLoad, this);
4973 um.on('failure', this.onLoad, this);
4974 this.removeMask = true;
4978 Roo.LoadMask.prototype = {
4980 * @cfg {Boolean} removeMask
4981 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4982 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4986 * The text to display in a centered loading message box (defaults to 'Loading...')
4990 * @cfg {String} msgCls
4991 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4993 msgCls : 'x-mask-loading',
4996 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5002 * Disables the mask to prevent it from being displayed
5004 disable : function(){
5005 this.disabled = true;
5009 * Enables the mask so that it can be displayed
5011 enable : function(){
5012 this.disabled = false;
5015 onLoadException : function()
5019 if (typeof(arguments[3]) != 'undefined') {
5020 Roo.MessageBox.alert("Error loading",arguments[3]);
5024 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5025 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5034 this.el.unmask(this.removeMask);
5039 this.el.unmask(this.removeMask);
5043 onBeforeLoad : function(){
5045 this.el.mask(this.msg, this.msgCls);
5050 destroy : function(){
5052 this.store.un('beforeload', this.onBeforeLoad, this);
5053 this.store.un('load', this.onLoad, this);
5054 this.store.un('loadexception', this.onLoadException, this);
5056 var um = this.el.getUpdateManager();
5057 um.un('beforeupdate', this.onBeforeLoad, this);
5058 um.un('update', this.onLoad, this);
5059 um.un('failure', this.onLoad, this);
5070 * @class Roo.bootstrap.Table
5071 * @extends Roo.bootstrap.Component
5072 * Bootstrap Table class
5073 * @cfg {String} cls table class
5074 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5075 * @cfg {String} bgcolor Specifies the background color for a table
5076 * @cfg {Number} border Specifies whether the table cells should have borders or not
5077 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5078 * @cfg {Number} cellspacing Specifies the space between cells
5079 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5080 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5081 * @cfg {String} sortable Specifies that the table should be sortable
5082 * @cfg {String} summary Specifies a summary of the content of a table
5083 * @cfg {Number} width Specifies the width of a table
5084 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5086 * @cfg {boolean} striped Should the rows be alternative striped
5087 * @cfg {boolean} bordered Add borders to the table
5088 * @cfg {boolean} hover Add hover highlighting
5089 * @cfg {boolean} condensed Format condensed
5090 * @cfg {boolean} responsive Format condensed
5091 * @cfg {Boolean} loadMask (true|false) default false
5092 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5093 * @cfg {Boolean} thead (true|false) generate thead, default true
5094 * @cfg {Boolean} RowSelection (true|false) default false
5095 * @cfg {Boolean} CellSelection (true|false) default false
5096 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5100 * Create a new Table
5101 * @param {Object} config The config object
5104 Roo.bootstrap.Table = function(config){
5105 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5108 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5109 this.sm = this.selModel;
5110 this.sm.xmodule = this.xmodule || false;
5112 if (this.cm && typeof(this.cm.config) == 'undefined') {
5113 this.colModel = new Roo.grid.ColumnModel(this.cm);
5114 this.cm = this.colModel;
5115 this.cm.xmodule = this.xmodule || false;
5118 this.store= Roo.factory(this.store, Roo.data);
5119 this.ds = this.store;
5120 this.ds.xmodule = this.xmodule || false;
5123 if (this.footer && this.store) {
5124 this.footer.dataSource = this.ds;
5125 this.footer = Roo.factory(this.footer);
5132 * Fires when a cell is clicked
5133 * @param {Roo.bootstrap.Table} this
5134 * @param {Roo.Element} el
5135 * @param {Number} rowIndex
5136 * @param {Number} columnIndex
5137 * @param {Roo.EventObject} e
5141 * @event celldblclick
5142 * Fires when a cell is double clicked
5143 * @param {Roo.bootstrap.Table} this
5144 * @param {Roo.Element} el
5145 * @param {Number} rowIndex
5146 * @param {Number} columnIndex
5147 * @param {Roo.EventObject} e
5149 "celldblclick" : true,
5152 * Fires when a row is clicked
5153 * @param {Roo.bootstrap.Table} this
5154 * @param {Roo.Element} el
5155 * @param {Number} rowIndex
5156 * @param {Roo.EventObject} e
5160 * @event rowdblclick
5161 * Fires when a row is double clicked
5162 * @param {Roo.bootstrap.Table} this
5163 * @param {Roo.Element} el
5164 * @param {Number} rowIndex
5165 * @param {Roo.EventObject} e
5167 "rowdblclick" : true,
5170 * Fires when a mouseover occur
5171 * @param {Roo.bootstrap.Table} this
5172 * @param {Roo.Element} el
5173 * @param {Number} rowIndex
5174 * @param {Number} columnIndex
5175 * @param {Roo.EventObject} e
5180 * Fires when a mouseout occur
5181 * @param {Roo.bootstrap.Table} this
5182 * @param {Roo.Element} el
5183 * @param {Number} rowIndex
5184 * @param {Number} columnIndex
5185 * @param {Roo.EventObject} e
5190 * Fires when a row is rendered, so you can change add a style to it.
5191 * @param {Roo.bootstrap.Table} this
5192 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5196 * @event rowsrendered
5197 * Fires when all the rows have been rendered
5198 * @param {Roo.bootstrap.Table} this
5200 'rowsrendered' : true
5205 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5229 RowSelection : false,
5230 CellSelection : false,
5233 // Roo.Element - the tbody
5236 getAutoCreate : function(){
5237 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5246 cfg.cls += ' table-striped';
5250 cfg.cls += ' table-hover';
5252 if (this.bordered) {
5253 cfg.cls += ' table-bordered';
5255 if (this.condensed) {
5256 cfg.cls += ' table-condensed';
5258 if (this.responsive) {
5259 cfg.cls += ' table-responsive';
5263 cfg.cls+= ' ' +this.cls;
5266 // this lot should be simplifed...
5269 cfg.align=this.align;
5272 cfg.bgcolor=this.bgcolor;
5275 cfg.border=this.border;
5277 if (this.cellpadding) {
5278 cfg.cellpadding=this.cellpadding;
5280 if (this.cellspacing) {
5281 cfg.cellspacing=this.cellspacing;
5284 cfg.frame=this.frame;
5287 cfg.rules=this.rules;
5289 if (this.sortable) {
5290 cfg.sortable=this.sortable;
5293 cfg.summary=this.summary;
5296 cfg.width=this.width;
5299 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5302 if(this.store || this.cm){
5304 cfg.cn.push(this.renderHeader());
5307 cfg.cn.push(this.renderBody());
5310 cfg.cn.push(this.renderFooter());
5313 cfg.cls+= ' TableGrid';
5316 return { cn : [ cfg ] };
5319 initEvents : function()
5321 if(!this.store || !this.cm){
5325 //Roo.log('initEvents with ds!!!!');
5327 this.mainBody = this.el.select('tbody', true).first();
5332 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5333 e.on('click', _this.sort, _this);
5336 this.el.on("click", this.onClick, this);
5337 this.el.on("dblclick", this.onDblClick, this);
5339 // why is this done????? = it breaks dialogs??
5340 //this.parent().el.setStyle('position', 'relative');
5344 this.footer.parentId = this.id;
5345 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5348 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5350 this.store.on('load', this.onLoad, this);
5351 this.store.on('beforeload', this.onBeforeLoad, this);
5352 this.store.on('update', this.onUpdate, this);
5353 this.store.on('add', this.onAdd, this);
5357 onMouseover : function(e, el)
5359 var cell = Roo.get(el);
5365 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5366 cell = cell.findParent('td', false, true);
5369 var row = cell.findParent('tr', false, true);
5370 var cellIndex = cell.dom.cellIndex;
5371 var rowIndex = row.dom.rowIndex - 1; // start from 0
5373 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5377 onMouseout : function(e, el)
5379 var cell = Roo.get(el);
5385 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5386 cell = cell.findParent('td', false, true);
5389 var row = cell.findParent('tr', false, true);
5390 var cellIndex = cell.dom.cellIndex;
5391 var rowIndex = row.dom.rowIndex - 1; // start from 0
5393 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5397 onClick : function(e, el)
5399 var cell = Roo.get(el);
5401 if(!cell || (!this.CellSelection && !this.RowSelection)){
5405 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5406 cell = cell.findParent('td', false, true);
5409 if(!cell || typeof(cell) == 'undefined'){
5413 var row = cell.findParent('tr', false, true);
5415 if(!row || typeof(row) == 'undefined'){
5419 var cellIndex = cell.dom.cellIndex;
5420 var rowIndex = this.getRowIndex(row);
5422 if(this.CellSelection){
5423 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5426 if(this.RowSelection){
5427 this.fireEvent('rowclick', this, row, rowIndex, e);
5433 onDblClick : function(e,el)
5435 var cell = Roo.get(el);
5437 if(!cell || (!this.CellSelection && !this.RowSelection)){
5441 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5442 cell = cell.findParent('td', false, true);
5445 if(!cell || typeof(cell) == 'undefined'){
5449 var row = cell.findParent('tr', false, true);
5451 if(!row || typeof(row) == 'undefined'){
5455 var cellIndex = cell.dom.cellIndex;
5456 var rowIndex = this.getRowIndex(row);
5458 if(this.CellSelection){
5459 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5462 if(this.RowSelection){
5463 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5467 sort : function(e,el)
5469 var col = Roo.get(el);
5471 if(!col.hasClass('sortable')){
5475 var sort = col.attr('sort');
5478 if(col.hasClass('glyphicon-arrow-up')){
5482 this.store.sortInfo = {field : sort, direction : dir};
5485 Roo.log("calling footer first");
5486 this.footer.onClick('first');
5489 this.store.load({ params : { start : 0 } });
5493 renderHeader : function()
5502 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5504 var config = cm.config[i];
5509 html: cm.getColumnHeader(i)
5512 if(typeof(config.tooltip) != 'undefined'){
5513 c.tooltip = config.tooltip;
5516 if(typeof(config.colspan) != 'undefined'){
5517 c.colspan = config.colspan;
5520 if(typeof(config.hidden) != 'undefined' && config.hidden){
5521 c.style += ' display:none;';
5524 if(typeof(config.dataIndex) != 'undefined'){
5525 c.sort = config.dataIndex;
5528 if(typeof(config.sortable) != 'undefined' && config.sortable){
5532 if(typeof(config.align) != 'undefined' && config.align.length){
5533 c.style += ' text-align:' + config.align + ';';
5536 if(typeof(config.width) != 'undefined'){
5537 c.style += ' width:' + config.width + 'px;';
5546 renderBody : function()
5556 colspan : this.cm.getColumnCount()
5566 renderFooter : function()
5576 colspan : this.cm.getColumnCount()
5590 Roo.log('ds onload');
5595 var ds = this.store;
5597 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5598 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5600 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5601 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5604 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5605 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5609 var tbody = this.mainBody;
5611 if(ds.getCount() > 0){
5612 ds.data.each(function(d,rowIndex){
5613 var row = this.renderRow(cm, ds, rowIndex);
5615 tbody.createChild(row);
5619 if(row.cellObjects.length){
5620 Roo.each(row.cellObjects, function(r){
5621 _this.renderCellObject(r);
5628 Roo.each(this.el.select('tbody td', true).elements, function(e){
5629 e.on('mouseover', _this.onMouseover, _this);
5632 Roo.each(this.el.select('tbody td', true).elements, function(e){
5633 e.on('mouseout', _this.onMouseout, _this);
5635 this.fireEvent('rowsrendered', this);
5636 //if(this.loadMask){
5637 // this.maskEl.hide();
5642 onUpdate : function(ds,record)
5644 this.refreshRow(record);
5647 onRemove : function(ds, record, index, isUpdate){
5648 if(isUpdate !== true){
5649 this.fireEvent("beforerowremoved", this, index, record);
5651 var bt = this.mainBody.dom;
5653 var rows = this.el.select('tbody > tr', true).elements;
5655 if(typeof(rows[index]) != 'undefined'){
5656 bt.removeChild(rows[index].dom);
5659 // if(bt.rows[index]){
5660 // bt.removeChild(bt.rows[index]);
5663 if(isUpdate !== true){
5664 //this.stripeRows(index);
5665 //this.syncRowHeights(index, index);
5667 this.fireEvent("rowremoved", this, index, record);
5671 onAdd : function(ds, records, rowIndex)
5673 //Roo.log('on Add called');
5674 // - note this does not handle multiple adding very well..
5675 var bt = this.mainBody.dom;
5676 for (var i =0 ; i < records.length;i++) {
5677 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5678 //Roo.log(records[i]);
5679 //Roo.log(this.store.getAt(rowIndex+i));
5680 this.insertRow(this.store, rowIndex + i, false);
5687 refreshRow : function(record){
5688 var ds = this.store, index;
5689 if(typeof record == 'number'){
5691 record = ds.getAt(index);
5693 index = ds.indexOf(record);
5695 this.insertRow(ds, index, true);
5696 this.onRemove(ds, record, index+1, true);
5697 //this.syncRowHeights(index, index);
5699 this.fireEvent("rowupdated", this, index, record);
5702 insertRow : function(dm, rowIndex, isUpdate){
5705 this.fireEvent("beforerowsinserted", this, rowIndex);
5707 //var s = this.getScrollState();
5708 var row = this.renderRow(this.cm, this.store, rowIndex);
5709 // insert before rowIndex..
5710 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5714 if(row.cellObjects.length){
5715 Roo.each(row.cellObjects, function(r){
5716 _this.renderCellObject(r);
5721 this.fireEvent("rowsinserted", this, rowIndex);
5722 //this.syncRowHeights(firstRow, lastRow);
5723 //this.stripeRows(firstRow);
5730 getRowDom : function(rowIndex)
5732 var rows = this.el.select('tbody > tr', true).elements;
5734 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5737 // returns the object tree for a tr..
5740 renderRow : function(cm, ds, rowIndex)
5743 var d = ds.getAt(rowIndex);
5750 var cellObjects = [];
5752 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5753 var config = cm.config[i];
5755 var renderer = cm.getRenderer(i);
5759 if(typeof(renderer) !== 'undefined'){
5760 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5762 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5763 // and are rendered into the cells after the row is rendered - using the id for the element.
5765 if(typeof(value) === 'object'){
5775 rowIndex : rowIndex,
5780 this.fireEvent('rowclass', this, rowcfg);
5784 cls : rowcfg.rowClass,
5786 html: (typeof(value) === 'object') ? '' : value
5793 if(typeof(config.colspan) != 'undefined'){
5794 td.colspan = config.colspan;
5797 if(typeof(config.hidden) != 'undefined' && config.hidden){
5798 td.style += ' display:none;';
5801 if(typeof(config.align) != 'undefined' && config.align.length){
5802 td.style += ' text-align:' + config.align + ';';
5805 if(typeof(config.width) != 'undefined'){
5806 td.style += ' width:' + config.width + 'px;';
5809 if(typeof(config.cursor) != 'undefined'){
5810 td.style += ' cursor:' + config.cursor + ';';
5817 row.cellObjects = cellObjects;
5825 onBeforeLoad : function()
5827 //Roo.log('ds onBeforeLoad');
5831 //if(this.loadMask){
5832 // this.maskEl.show();
5840 this.el.select('tbody', true).first().dom.innerHTML = '';
5843 * Show or hide a row.
5844 * @param {Number} rowIndex to show or hide
5845 * @param {Boolean} state hide
5847 setRowVisibility : function(rowIndex, state)
5849 var bt = this.mainBody.dom;
5851 var rows = this.el.select('tbody > tr', true).elements;
5853 if(typeof(rows[rowIndex]) == 'undefined'){
5856 rows[rowIndex].dom.style.display = state ? '' : 'none';
5860 getSelectionModel : function(){
5862 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5864 return this.selModel;
5867 * Render the Roo.bootstrap object from renderder
5869 renderCellObject : function(r)
5873 var t = r.cfg.render(r.container);
5876 Roo.each(r.cfg.cn, function(c){
5878 container: t.getChildContainer(),
5881 _this.renderCellObject(child);
5886 getRowIndex : function(row)
5890 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5913 * @class Roo.bootstrap.TableCell
5914 * @extends Roo.bootstrap.Component
5915 * Bootstrap TableCell class
5916 * @cfg {String} html cell contain text
5917 * @cfg {String} cls cell class
5918 * @cfg {String} tag cell tag (td|th) default td
5919 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5920 * @cfg {String} align Aligns the content in a cell
5921 * @cfg {String} axis Categorizes cells
5922 * @cfg {String} bgcolor Specifies the background color of a cell
5923 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5924 * @cfg {Number} colspan Specifies the number of columns a cell should span
5925 * @cfg {String} headers Specifies one or more header cells a cell is related to
5926 * @cfg {Number} height Sets the height of a cell
5927 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5928 * @cfg {Number} rowspan Sets the number of rows a cell should span
5929 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5930 * @cfg {String} valign Vertical aligns the content in a cell
5931 * @cfg {Number} width Specifies the width of a cell
5934 * Create a new TableCell
5935 * @param {Object} config The config object
5938 Roo.bootstrap.TableCell = function(config){
5939 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5942 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5962 getAutoCreate : function(){
5963 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5983 cfg.align=this.align
5989 cfg.bgcolor=this.bgcolor
5992 cfg.charoff=this.charoff
5995 cfg.colspan=this.colspan
5998 cfg.headers=this.headers
6001 cfg.height=this.height
6004 cfg.nowrap=this.nowrap
6007 cfg.rowspan=this.rowspan
6010 cfg.scope=this.scope
6013 cfg.valign=this.valign
6016 cfg.width=this.width
6035 * @class Roo.bootstrap.TableRow
6036 * @extends Roo.bootstrap.Component
6037 * Bootstrap TableRow class
6038 * @cfg {String} cls row class
6039 * @cfg {String} align Aligns the content in a table row
6040 * @cfg {String} bgcolor Specifies a background color for a table row
6041 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6042 * @cfg {String} valign Vertical aligns the content in a table row
6045 * Create a new TableRow
6046 * @param {Object} config The config object
6049 Roo.bootstrap.TableRow = function(config){
6050 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6053 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6061 getAutoCreate : function(){
6062 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6072 cfg.align = this.align;
6075 cfg.bgcolor = this.bgcolor;
6078 cfg.charoff = this.charoff;
6081 cfg.valign = this.valign;
6099 * @class Roo.bootstrap.TableBody
6100 * @extends Roo.bootstrap.Component
6101 * Bootstrap TableBody class
6102 * @cfg {String} cls element class
6103 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6104 * @cfg {String} align Aligns the content inside the element
6105 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6106 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6109 * Create a new TableBody
6110 * @param {Object} config The config object
6113 Roo.bootstrap.TableBody = function(config){
6114 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6117 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6125 getAutoCreate : function(){
6126 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6140 cfg.align = this.align;
6143 cfg.charoff = this.charoff;
6146 cfg.valign = this.valign;
6153 // initEvents : function()
6160 // this.store = Roo.factory(this.store, Roo.data);
6161 // this.store.on('load', this.onLoad, this);
6163 // this.store.load();
6167 // onLoad: function ()
6169 // this.fireEvent('load', this);
6179 * Ext JS Library 1.1.1
6180 * Copyright(c) 2006-2007, Ext JS, LLC.
6182 * Originally Released Under LGPL - original licence link has changed is not relivant.
6185 * <script type="text/javascript">
6188 // as we use this in bootstrap.
6189 Roo.namespace('Roo.form');
6191 * @class Roo.form.Action
6192 * Internal Class used to handle form actions
6194 * @param {Roo.form.BasicForm} el The form element or its id
6195 * @param {Object} config Configuration options
6200 // define the action interface
6201 Roo.form.Action = function(form, options){
6203 this.options = options || {};
6206 * Client Validation Failed
6209 Roo.form.Action.CLIENT_INVALID = 'client';
6211 * Server Validation Failed
6214 Roo.form.Action.SERVER_INVALID = 'server';
6216 * Connect to Server Failed
6219 Roo.form.Action.CONNECT_FAILURE = 'connect';
6221 * Reading Data from Server Failed
6224 Roo.form.Action.LOAD_FAILURE = 'load';
6226 Roo.form.Action.prototype = {
6228 failureType : undefined,
6229 response : undefined,
6233 run : function(options){
6238 success : function(response){
6243 handleResponse : function(response){
6247 // default connection failure
6248 failure : function(response){
6250 this.response = response;
6251 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6252 this.form.afterAction(this, false);
6255 processResponse : function(response){
6256 this.response = response;
6257 if(!response.responseText){
6260 this.result = this.handleResponse(response);
6264 // utility functions used internally
6265 getUrl : function(appendParams){
6266 var url = this.options.url || this.form.url || this.form.el.dom.action;
6268 var p = this.getParams();
6270 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6276 getMethod : function(){
6277 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6280 getParams : function(){
6281 var bp = this.form.baseParams;
6282 var p = this.options.params;
6284 if(typeof p == "object"){
6285 p = Roo.urlEncode(Roo.applyIf(p, bp));
6286 }else if(typeof p == 'string' && bp){
6287 p += '&' + Roo.urlEncode(bp);
6290 p = Roo.urlEncode(bp);
6295 createCallback : function(){
6297 success: this.success,
6298 failure: this.failure,
6300 timeout: (this.form.timeout*1000),
6301 upload: this.form.fileUpload ? this.success : undefined
6306 Roo.form.Action.Submit = function(form, options){
6307 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6310 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6313 haveProgress : false,
6314 uploadComplete : false,
6316 // uploadProgress indicator.
6317 uploadProgress : function()
6319 if (!this.form.progressUrl) {
6323 if (!this.haveProgress) {
6324 Roo.MessageBox.progress("Uploading", "Uploading");
6326 if (this.uploadComplete) {
6327 Roo.MessageBox.hide();
6331 this.haveProgress = true;
6333 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6335 var c = new Roo.data.Connection();
6337 url : this.form.progressUrl,
6342 success : function(req){
6343 //console.log(data);
6347 rdata = Roo.decode(req.responseText)
6349 Roo.log("Invalid data from server..");
6353 if (!rdata || !rdata.success) {
6355 Roo.MessageBox.alert(Roo.encode(rdata));
6358 var data = rdata.data;
6360 if (this.uploadComplete) {
6361 Roo.MessageBox.hide();
6366 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6367 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6370 this.uploadProgress.defer(2000,this);
6373 failure: function(data) {
6374 Roo.log('progress url failed ');
6385 // run get Values on the form, so it syncs any secondary forms.
6386 this.form.getValues();
6388 var o = this.options;
6389 var method = this.getMethod();
6390 var isPost = method == 'POST';
6391 if(o.clientValidation === false || this.form.isValid()){
6393 if (this.form.progressUrl) {
6394 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6395 (new Date() * 1) + '' + Math.random());
6400 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6401 form:this.form.el.dom,
6402 url:this.getUrl(!isPost),
6404 params:isPost ? this.getParams() : null,
6405 isUpload: this.form.fileUpload
6408 this.uploadProgress();
6410 }else if (o.clientValidation !== false){ // client validation failed
6411 this.failureType = Roo.form.Action.CLIENT_INVALID;
6412 this.form.afterAction(this, false);
6416 success : function(response)
6418 this.uploadComplete= true;
6419 if (this.haveProgress) {
6420 Roo.MessageBox.hide();
6424 var result = this.processResponse(response);
6425 if(result === true || result.success){
6426 this.form.afterAction(this, true);
6430 this.form.markInvalid(result.errors);
6431 this.failureType = Roo.form.Action.SERVER_INVALID;
6433 this.form.afterAction(this, false);
6435 failure : function(response)
6437 this.uploadComplete= true;
6438 if (this.haveProgress) {
6439 Roo.MessageBox.hide();
6442 this.response = response;
6443 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6444 this.form.afterAction(this, false);
6447 handleResponse : function(response){
6448 if(this.form.errorReader){
6449 var rs = this.form.errorReader.read(response);
6452 for(var i = 0, len = rs.records.length; i < len; i++) {
6453 var r = rs.records[i];
6457 if(errors.length < 1){
6461 success : rs.success,
6467 ret = Roo.decode(response.responseText);
6471 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6481 Roo.form.Action.Load = function(form, options){
6482 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6483 this.reader = this.form.reader;
6486 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6491 Roo.Ajax.request(Roo.apply(
6492 this.createCallback(), {
6493 method:this.getMethod(),
6494 url:this.getUrl(false),
6495 params:this.getParams()
6499 success : function(response){
6501 var result = this.processResponse(response);
6502 if(result === true || !result.success || !result.data){
6503 this.failureType = Roo.form.Action.LOAD_FAILURE;
6504 this.form.afterAction(this, false);
6507 this.form.clearInvalid();
6508 this.form.setValues(result.data);
6509 this.form.afterAction(this, true);
6512 handleResponse : function(response){
6513 if(this.form.reader){
6514 var rs = this.form.reader.read(response);
6515 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6517 success : rs.success,
6521 return Roo.decode(response.responseText);
6525 Roo.form.Action.ACTION_TYPES = {
6526 'load' : Roo.form.Action.Load,
6527 'submit' : Roo.form.Action.Submit
6536 * @class Roo.bootstrap.Form
6537 * @extends Roo.bootstrap.Component
6538 * Bootstrap Form class
6539 * @cfg {String} method GET | POST (default POST)
6540 * @cfg {String} labelAlign top | left (default top)
6541 * @cfg {String} align left | right - for navbars
6542 * @cfg {Boolean} loadMask load mask when submit (default true)
6547 * @param {Object} config The config object
6551 Roo.bootstrap.Form = function(config){
6552 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6555 * @event clientvalidation
6556 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6557 * @param {Form} this
6558 * @param {Boolean} valid true if the form has passed client-side validation
6560 clientvalidation: true,
6562 * @event beforeaction
6563 * Fires before any action is performed. Return false to cancel the action.
6564 * @param {Form} this
6565 * @param {Action} action The action to be performed
6569 * @event actionfailed
6570 * Fires when an action fails.
6571 * @param {Form} this
6572 * @param {Action} action The action that failed
6574 actionfailed : true,
6576 * @event actioncomplete
6577 * Fires when an action is completed.
6578 * @param {Form} this
6579 * @param {Action} action The action that completed
6581 actioncomplete : true
6586 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6589 * @cfg {String} method
6590 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6595 * The URL to use for form actions if one isn't supplied in the action options.
6598 * @cfg {Boolean} fileUpload
6599 * Set to true if this form is a file upload.
6603 * @cfg {Object} baseParams
6604 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6608 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6612 * @cfg {Sting} align (left|right) for navbar forms
6617 activeAction : null,
6620 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6621 * element by passing it or its id or mask the form itself by passing in true.
6624 waitMsgTarget : false,
6628 getAutoCreate : function(){
6632 method : this.method || 'POST',
6633 id : this.id || Roo.id(),
6636 if (this.parent().xtype.match(/^Nav/)) {
6637 cfg.cls = 'navbar-form navbar-' + this.align;
6641 if (this.labelAlign == 'left' ) {
6642 cfg.cls += ' form-horizontal';
6648 initEvents : function()
6650 this.el.on('submit', this.onSubmit, this);
6651 // this was added as random key presses on the form where triggering form submit.
6652 this.el.on('keypress', function(e) {
6653 if (e.getCharCode() != 13) {
6656 // we might need to allow it for textareas.. and some other items.
6657 // check e.getTarget().
6659 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6663 Roo.log("keypress blocked");
6671 onSubmit : function(e){
6676 * Returns true if client-side validation on the form is successful.
6679 isValid : function(){
6680 var items = this.getItems();
6682 items.each(function(f){
6691 * Returns true if any fields in this form have changed since their original load.
6694 isDirty : function(){
6696 var items = this.getItems();
6697 items.each(function(f){
6707 * Performs a predefined action (submit or load) or custom actions you define on this form.
6708 * @param {String} actionName The name of the action type
6709 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6710 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6711 * accept other config options):
6713 Property Type Description
6714 ---------------- --------------- ----------------------------------------------------------------------------------
6715 url String The url for the action (defaults to the form's url)
6716 method String The form method to use (defaults to the form's method, or POST if not defined)
6717 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6718 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6719 validate the form on the client (defaults to false)
6721 * @return {BasicForm} this
6723 doAction : function(action, options){
6724 if(typeof action == 'string'){
6725 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6727 if(this.fireEvent('beforeaction', this, action) !== false){
6728 this.beforeAction(action);
6729 action.run.defer(100, action);
6735 beforeAction : function(action){
6736 var o = action.options;
6739 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6741 // not really supported yet.. ??
6743 //if(this.waitMsgTarget === true){
6744 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6745 //}else if(this.waitMsgTarget){
6746 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6747 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6749 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6755 afterAction : function(action, success){
6756 this.activeAction = null;
6757 var o = action.options;
6759 //if(this.waitMsgTarget === true){
6761 //}else if(this.waitMsgTarget){
6762 // this.waitMsgTarget.unmask();
6764 // Roo.MessageBox.updateProgress(1);
6765 // Roo.MessageBox.hide();
6772 Roo.callback(o.success, o.scope, [this, action]);
6773 this.fireEvent('actioncomplete', this, action);
6777 // failure condition..
6778 // we have a scenario where updates need confirming.
6779 // eg. if a locking scenario exists..
6780 // we look for { errors : { needs_confirm : true }} in the response.
6782 (typeof(action.result) != 'undefined') &&
6783 (typeof(action.result.errors) != 'undefined') &&
6784 (typeof(action.result.errors.needs_confirm) != 'undefined')
6787 Roo.log("not supported yet");
6790 Roo.MessageBox.confirm(
6791 "Change requires confirmation",
6792 action.result.errorMsg,
6797 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6807 Roo.callback(o.failure, o.scope, [this, action]);
6808 // show an error message if no failed handler is set..
6809 if (!this.hasListener('actionfailed')) {
6810 Roo.log("need to add dialog support");
6812 Roo.MessageBox.alert("Error",
6813 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6814 action.result.errorMsg :
6815 "Saving Failed, please check your entries or try again"
6820 this.fireEvent('actionfailed', this, action);
6825 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6826 * @param {String} id The value to search for
6829 findField : function(id){
6830 var items = this.getItems();
6831 var field = items.get(id);
6833 items.each(function(f){
6834 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6841 return field || null;
6844 * Mark fields in this form invalid in bulk.
6845 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6846 * @return {BasicForm} this
6848 markInvalid : function(errors){
6849 if(errors instanceof Array){
6850 for(var i = 0, len = errors.length; i < len; i++){
6851 var fieldError = errors[i];
6852 var f = this.findField(fieldError.id);
6854 f.markInvalid(fieldError.msg);
6860 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6861 field.markInvalid(errors[id]);
6865 //Roo.each(this.childForms || [], function (f) {
6866 // f.markInvalid(errors);
6873 * Set values for fields in this form in bulk.
6874 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6875 * @return {BasicForm} this
6877 setValues : function(values){
6878 if(values instanceof Array){ // array of objects
6879 for(var i = 0, len = values.length; i < len; i++){
6881 var f = this.findField(v.id);
6883 f.setValue(v.value);
6884 if(this.trackResetOnLoad){
6885 f.originalValue = f.getValue();
6889 }else{ // object hash
6892 if(typeof values[id] != 'function' && (field = this.findField(id))){
6894 if (field.setFromData &&
6896 field.displayField &&
6897 // combos' with local stores can
6898 // be queried via setValue()
6899 // to set their value..
6900 (field.store && !field.store.isLocal)
6904 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6905 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6906 field.setFromData(sd);
6909 field.setValue(values[id]);
6913 if(this.trackResetOnLoad){
6914 field.originalValue = field.getValue();
6920 //Roo.each(this.childForms || [], function (f) {
6921 // f.setValues(values);
6928 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6929 * they are returned as an array.
6930 * @param {Boolean} asString
6933 getValues : function(asString){
6934 //if (this.childForms) {
6935 // copy values from the child forms
6936 // Roo.each(this.childForms, function (f) {
6937 // this.setValues(f.getValues());
6943 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6944 if(asString === true){
6947 return Roo.urlDecode(fs);
6951 * Returns the fields in this form as an object with key/value pairs.
6952 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6955 getFieldValues : function(with_hidden)
6957 var items = this.getItems();
6959 items.each(function(f){
6963 var v = f.getValue();
6964 if (f.inputType =='radio') {
6965 if (typeof(ret[f.getName()]) == 'undefined') {
6966 ret[f.getName()] = ''; // empty..
6969 if (!f.el.dom.checked) {
6977 // not sure if this supported any more..
6978 if ((typeof(v) == 'object') && f.getRawValue) {
6979 v = f.getRawValue() ; // dates..
6981 // combo boxes where name != hiddenName...
6982 if (f.name != f.getName()) {
6983 ret[f.name] = f.getRawValue();
6985 ret[f.getName()] = v;
6992 * Clears all invalid messages in this form.
6993 * @return {BasicForm} this
6995 clearInvalid : function(){
6996 var items = this.getItems();
6998 items.each(function(f){
7009 * @return {BasicForm} this
7012 var items = this.getItems();
7013 items.each(function(f){
7017 Roo.each(this.childForms || [], function (f) {
7024 getItems : function()
7026 var r=new Roo.util.MixedCollection(false, function(o){
7027 return o.id || (o.id = Roo.id());
7029 var iter = function(el) {
7036 Roo.each(el.items,function(e) {
7056 * Ext JS Library 1.1.1
7057 * Copyright(c) 2006-2007, Ext JS, LLC.
7059 * Originally Released Under LGPL - original licence link has changed is not relivant.
7062 * <script type="text/javascript">
7065 * @class Roo.form.VTypes
7066 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7069 Roo.form.VTypes = function(){
7070 // closure these in so they are only created once.
7071 var alpha = /^[a-zA-Z_]+$/;
7072 var alphanum = /^[a-zA-Z0-9_]+$/;
7073 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7074 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7076 // All these messages and functions are configurable
7079 * The function used to validate email addresses
7080 * @param {String} value The email address
7082 'email' : function(v){
7083 return email.test(v);
7086 * The error text to display when the email validation function returns false
7089 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7091 * The keystroke filter mask to be applied on email input
7094 'emailMask' : /[a-z0-9_\.\-@]/i,
7097 * The function used to validate URLs
7098 * @param {String} value The URL
7100 'url' : function(v){
7104 * The error text to display when the url validation function returns false
7107 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7110 * The function used to validate alpha values
7111 * @param {String} value The value
7113 'alpha' : function(v){
7114 return alpha.test(v);
7117 * The error text to display when the alpha validation function returns false
7120 'alphaText' : 'This field should only contain letters and _',
7122 * The keystroke filter mask to be applied on alpha input
7125 'alphaMask' : /[a-z_]/i,
7128 * The function used to validate alphanumeric values
7129 * @param {String} value The value
7131 'alphanum' : function(v){
7132 return alphanum.test(v);
7135 * The error text to display when the alphanumeric validation function returns false
7138 'alphanumText' : 'This field should only contain letters, numbers and _',
7140 * The keystroke filter mask to be applied on alphanumeric input
7143 'alphanumMask' : /[a-z0-9_]/i
7153 * @class Roo.bootstrap.Input
7154 * @extends Roo.bootstrap.Component
7155 * Bootstrap Input class
7156 * @cfg {Boolean} disabled is it disabled
7157 * @cfg {String} fieldLabel - the label associated
7158 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7159 * @cfg {String} name name of the input
7160 * @cfg {string} fieldLabel - the label associated
7161 * @cfg {string} inputType - input / file submit ...
7162 * @cfg {string} placeholder - placeholder to put in text.
7163 * @cfg {string} before - input group add on before
7164 * @cfg {string} after - input group add on after
7165 * @cfg {string} size - (lg|sm) or leave empty..
7166 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7167 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7168 * @cfg {Number} md colspan out of 12 for computer-sized screens
7169 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7170 * @cfg {string} value default value of the input
7171 * @cfg {Number} labelWidth set the width of label (0-12)
7172 * @cfg {String} labelAlign (top|left)
7173 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7174 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7176 * @cfg {String} align (left|center|right) Default left
7181 * Create a new Input
7182 * @param {Object} config The config object
7185 Roo.bootstrap.Input = function(config){
7186 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7191 * Fires when this field receives input focus.
7192 * @param {Roo.form.Field} this
7197 * Fires when this field loses input focus.
7198 * @param {Roo.form.Field} this
7203 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7204 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7205 * @param {Roo.form.Field} this
7206 * @param {Roo.EventObject} e The event object
7211 * Fires just before the field blurs if the field value has changed.
7212 * @param {Roo.form.Field} this
7213 * @param {Mixed} newValue The new value
7214 * @param {Mixed} oldValue The original value
7219 * Fires after the field has been marked as invalid.
7220 * @param {Roo.form.Field} this
7221 * @param {String} msg The validation message
7226 * Fires after the field has been validated with no errors.
7227 * @param {Roo.form.Field} this
7232 * Fires after the key up
7233 * @param {Roo.form.Field} this
7234 * @param {Roo.EventObject} e The event Object
7240 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7242 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7243 automatic validation (defaults to "keyup").
7245 validationEvent : "keyup",
7247 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7249 validateOnBlur : true,
7251 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7253 validationDelay : 250,
7255 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7257 focusClass : "x-form-focus", // not needed???
7261 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7263 invalidClass : "has-warning",
7266 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7268 validClass : "has-success",
7271 * @cfg {Boolean} hasFeedback (true|false) default true
7276 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7278 invalidFeedbackClass : "glyphicon-warning-sign",
7281 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7283 validFeedbackClass : "glyphicon-ok",
7286 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7288 selectOnFocus : false,
7291 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7295 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7300 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7302 disableKeyFilter : false,
7305 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7309 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7313 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7315 blankText : "This field is required",
7318 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7322 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7324 maxLength : Number.MAX_VALUE,
7326 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7328 minLengthText : "The minimum length for this field is {0}",
7330 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7332 maxLengthText : "The maximum length for this field is {0}",
7336 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7337 * If available, this function will be called only after the basic validators all return true, and will be passed the
7338 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7342 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7343 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7344 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7348 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7352 autocomplete: false,
7371 formatedValue : false,
7373 parentLabelAlign : function()
7376 while (parent.parent()) {
7377 parent = parent.parent();
7378 if (typeof(parent.labelAlign) !='undefined') {
7379 return parent.labelAlign;
7386 getAutoCreate : function(){
7388 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7394 if(this.inputType != 'hidden'){
7395 cfg.cls = 'form-group' //input-group
7401 type : this.inputType,
7403 cls : 'form-control',
7404 placeholder : this.placeholder || '',
7405 autocomplete : this.autocomplete || 'new-password'
7410 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7413 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7414 input.maxLength = this.maxLength;
7417 if (this.disabled) {
7418 input.disabled=true;
7421 if (this.readOnly) {
7422 input.readonly=true;
7426 input.name = this.name;
7429 input.cls += ' input-' + this.size;
7432 ['xs','sm','md','lg'].map(function(size){
7433 if (settings[size]) {
7434 cfg.cls += ' col-' + size + '-' + settings[size];
7438 var inputblock = input;
7440 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7444 cls: 'glyphicon form-control-feedback'
7448 cls : 'has-feedback',
7456 // var inputblock = input;
7458 if (this.before || this.after) {
7461 cls : 'input-group',
7465 if (this.before && typeof(this.before) == 'string') {
7467 inputblock.cn.push({
7469 cls : 'roo-input-before input-group-addon',
7473 if (this.before && typeof(this.before) == 'object') {
7474 this.before = Roo.factory(this.before);
7475 Roo.log(this.before);
7476 inputblock.cn.push({
7478 cls : 'roo-input-before input-group-' +
7479 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7483 inputblock.cn.push(input);
7485 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7486 inputblock.cls += ' has-feedback';
7487 inputblock.cn.push(feedback);
7490 if (this.after && typeof(this.after) == 'string') {
7491 inputblock.cn.push({
7493 cls : 'roo-input-after input-group-addon',
7497 if (this.after && typeof(this.after) == 'object') {
7498 this.after = Roo.factory(this.after);
7499 Roo.log(this.after);
7500 inputblock.cn.push({
7502 cls : 'roo-input-after input-group-' +
7503 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7508 if (align ==='left' && this.fieldLabel.length) {
7509 Roo.log("left and has label");
7515 cls : 'control-label col-sm-' + this.labelWidth,
7516 html : this.fieldLabel
7520 cls : "col-sm-" + (12 - this.labelWidth),
7527 } else if ( this.fieldLabel.length) {
7533 //cls : 'input-group-addon',
7534 html : this.fieldLabel
7544 Roo.log(" no label && no align");
7553 Roo.log('input-parentType: ' + this.parentType);
7555 if (this.parentType === 'Navbar' && this.parent().bar) {
7556 cfg.cls += ' navbar-form';
7564 * return the real input element.
7566 inputEl: function ()
7568 return this.el.select('input.form-control',true).first();
7571 tooltipEl : function()
7573 return this.inputEl();
7576 setDisabled : function(v)
7578 var i = this.inputEl().dom;
7580 i.removeAttribute('disabled');
7584 i.setAttribute('disabled','true');
7586 initEvents : function()
7589 this.inputEl().on("keydown" , this.fireKey, this);
7590 this.inputEl().on("focus", this.onFocus, this);
7591 this.inputEl().on("blur", this.onBlur, this);
7593 this.inputEl().relayEvent('keyup', this);
7595 // reference to original value for reset
7596 this.originalValue = this.getValue();
7597 //Roo.form.TextField.superclass.initEvents.call(this);
7598 if(this.validationEvent == 'keyup'){
7599 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7600 this.inputEl().on('keyup', this.filterValidation, this);
7602 else if(this.validationEvent !== false){
7603 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7606 if(this.selectOnFocus){
7607 this.on("focus", this.preFocus, this);
7610 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7611 this.inputEl().on("keypress", this.filterKeys, this);
7614 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7615 this.el.on("click", this.autoSize, this);
7618 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7619 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7622 if (typeof(this.before) == 'object') {
7623 this.before.render(this.el.select('.roo-input-before',true).first());
7625 if (typeof(this.after) == 'object') {
7626 this.after.render(this.el.select('.roo-input-after',true).first());
7631 filterValidation : function(e){
7632 if(!e.isNavKeyPress()){
7633 this.validationTask.delay(this.validationDelay);
7637 * Validates the field value
7638 * @return {Boolean} True if the value is valid, else false
7640 validate : function(){
7641 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7642 if(this.disabled || this.validateValue(this.getRawValue())){
7653 * Validates a value according to the field's validation rules and marks the field as invalid
7654 * if the validation fails
7655 * @param {Mixed} value The value to validate
7656 * @return {Boolean} True if the value is valid, else false
7658 validateValue : function(value){
7659 if(value.length < 1) { // if it's blank
7660 if(this.allowBlank){
7666 if(value.length < this.minLength){
7669 if(value.length > this.maxLength){
7673 var vt = Roo.form.VTypes;
7674 if(!vt[this.vtype](value, this)){
7678 if(typeof this.validator == "function"){
7679 var msg = this.validator(value);
7685 if(this.regex && !this.regex.test(value)){
7695 fireKey : function(e){
7696 //Roo.log('field ' + e.getKey());
7697 if(e.isNavKeyPress()){
7698 this.fireEvent("specialkey", this, e);
7701 focus : function (selectText){
7703 this.inputEl().focus();
7704 if(selectText === true){
7705 this.inputEl().dom.select();
7711 onFocus : function(){
7712 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7713 // this.el.addClass(this.focusClass);
7716 this.hasFocus = true;
7717 this.startValue = this.getValue();
7718 this.fireEvent("focus", this);
7722 beforeBlur : Roo.emptyFn,
7726 onBlur : function(){
7728 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7729 //this.el.removeClass(this.focusClass);
7731 this.hasFocus = false;
7732 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7735 var v = this.getValue();
7736 if(String(v) !== String(this.startValue)){
7737 this.fireEvent('change', this, v, this.startValue);
7739 this.fireEvent("blur", this);
7743 * Resets the current field value to the originally loaded value and clears any validation messages
7746 this.setValue(this.originalValue);
7750 * Returns the name of the field
7751 * @return {Mixed} name The name field
7753 getName: function(){
7757 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7758 * @return {Mixed} value The field value
7760 getValue : function(){
7762 var v = this.inputEl().getValue();
7767 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7768 * @return {Mixed} value The field value
7770 getRawValue : function(){
7771 var v = this.inputEl().getValue();
7777 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7778 * @param {Mixed} value The value to set
7780 setRawValue : function(v){
7781 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7784 selectText : function(start, end){
7785 var v = this.getRawValue();
7787 start = start === undefined ? 0 : start;
7788 end = end === undefined ? v.length : end;
7789 var d = this.inputEl().dom;
7790 if(d.setSelectionRange){
7791 d.setSelectionRange(start, end);
7792 }else if(d.createTextRange){
7793 var range = d.createTextRange();
7794 range.moveStart("character", start);
7795 range.moveEnd("character", v.length-end);
7802 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7803 * @param {Mixed} value The value to set
7805 setValue : function(v){
7808 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7814 processValue : function(value){
7815 if(this.stripCharsRe){
7816 var newValue = value.replace(this.stripCharsRe, '');
7817 if(newValue !== value){
7818 this.setRawValue(newValue);
7825 preFocus : function(){
7827 if(this.selectOnFocus){
7828 this.inputEl().dom.select();
7831 filterKeys : function(e){
7833 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7836 var c = e.getCharCode(), cc = String.fromCharCode(c);
7837 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7840 if(!this.maskRe.test(cc)){
7845 * Clear any invalid styles/messages for this field
7847 clearInvalid : function(){
7849 if(!this.el || this.preventMark){ // not rendered
7852 this.el.removeClass(this.invalidClass);
7854 this.fireEvent('valid', this);
7858 * Mark this field as valid
7860 markValid : function(){
7861 if(!this.el || this.preventMark){ // not rendered
7865 this.el.removeClass([this.invalidClass, this.validClass]);
7867 if(this.disabled || this.allowBlank){
7871 this.el.addClass(this.validClass);
7873 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7875 var feedback = this.el.select('.form-control-feedback', true).first();
7878 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7879 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7884 this.fireEvent('valid', this);
7888 * Mark this field as invalid
7889 * @param {String} msg The validation message
7891 markInvalid : function(msg){
7892 if(!this.el || this.preventMark){ // not rendered
7896 this.el.removeClass([this.invalidClass, this.validClass]);
7898 if(this.disabled || this.allowBlank){
7902 this.el.addClass(this.invalidClass);
7904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7906 var feedback = this.el.select('.form-control-feedback', true).first();
7909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7911 if(this.getValue().length){
7912 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7919 this.fireEvent('invalid', this, msg);
7922 SafariOnKeyDown : function(event)
7924 // this is a workaround for a password hang bug on chrome/ webkit.
7926 var isSelectAll = false;
7928 if(this.inputEl().dom.selectionEnd > 0){
7929 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7931 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7932 event.preventDefault();
7937 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7939 event.preventDefault();
7940 // this is very hacky as keydown always get's upper case.
7942 var cc = String.fromCharCode(event.getCharCode());
7943 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7947 adjustWidth : function(tag, w){
7948 tag = tag.toLowerCase();
7949 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7950 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7954 if(tag == 'textarea'){
7957 }else if(Roo.isOpera){
7961 if(tag == 'textarea'){
7980 * @class Roo.bootstrap.TextArea
7981 * @extends Roo.bootstrap.Input
7982 * Bootstrap TextArea class
7983 * @cfg {Number} cols Specifies the visible width of a text area
7984 * @cfg {Number} rows Specifies the visible number of lines in a text area
7985 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7986 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7987 * @cfg {string} html text
7990 * Create a new TextArea
7991 * @param {Object} config The config object
7994 Roo.bootstrap.TextArea = function(config){
7995 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7999 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8009 getAutoCreate : function(){
8011 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8022 value : this.value || '',
8023 html: this.html || '',
8024 cls : 'form-control',
8025 placeholder : this.placeholder || ''
8029 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8030 input.maxLength = this.maxLength;
8034 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8038 input.cols = this.cols;
8041 if (this.readOnly) {
8042 input.readonly = true;
8046 input.name = this.name;
8050 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8054 ['xs','sm','md','lg'].map(function(size){
8055 if (settings[size]) {
8056 cfg.cls += ' col-' + size + '-' + settings[size];
8060 var inputblock = input;
8062 if(this.hasFeedback && !this.allowBlank){
8066 cls: 'glyphicon form-control-feedback'
8070 cls : 'has-feedback',
8079 if (this.before || this.after) {
8082 cls : 'input-group',
8086 inputblock.cn.push({
8088 cls : 'input-group-addon',
8093 inputblock.cn.push(input);
8095 if(this.hasFeedback && !this.allowBlank){
8096 inputblock.cls += ' has-feedback';
8097 inputblock.cn.push(feedback);
8101 inputblock.cn.push({
8103 cls : 'input-group-addon',
8110 if (align ==='left' && this.fieldLabel.length) {
8111 Roo.log("left and has label");
8117 cls : 'control-label col-sm-' + this.labelWidth,
8118 html : this.fieldLabel
8122 cls : "col-sm-" + (12 - this.labelWidth),
8129 } else if ( this.fieldLabel.length) {
8135 //cls : 'input-group-addon',
8136 html : this.fieldLabel
8146 Roo.log(" no label && no align");
8156 if (this.disabled) {
8157 input.disabled=true;
8164 * return the real textarea element.
8166 inputEl: function ()
8168 return this.el.select('textarea.form-control',true).first();
8176 * trigger field - base class for combo..
8181 * @class Roo.bootstrap.TriggerField
8182 * @extends Roo.bootstrap.Input
8183 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8184 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8185 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8186 * for which you can provide a custom implementation. For example:
8188 var trigger = new Roo.bootstrap.TriggerField();
8189 trigger.onTriggerClick = myTriggerFn;
8190 trigger.applyTo('my-field');
8193 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8194 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8195 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8196 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8197 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8200 * Create a new TriggerField.
8201 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8202 * to the base TextField)
8204 Roo.bootstrap.TriggerField = function(config){
8205 this.mimicing = false;
8206 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8209 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8211 * @cfg {String} triggerClass A CSS class to apply to the trigger
8214 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8218 /** @cfg {Boolean} grow @hide */
8219 /** @cfg {Number} growMin @hide */
8220 /** @cfg {Number} growMax @hide */
8226 autoSize: Roo.emptyFn,
8233 actionMode : 'wrap',
8238 getAutoCreate : function(){
8240 var align = this.labelAlign || this.parentLabelAlign();
8245 cls: 'form-group' //input-group
8252 type : this.inputType,
8253 cls : 'form-control',
8254 autocomplete: 'new-password',
8255 placeholder : this.placeholder || ''
8259 input.name = this.name;
8262 input.cls += ' input-' + this.size;
8265 if (this.disabled) {
8266 input.disabled=true;
8269 var inputblock = input;
8271 if(this.hasFeedback && !this.allowBlank){
8275 cls: 'glyphicon form-control-feedback'
8279 cls : 'has-feedback',
8287 if (this.before || this.after) {
8290 cls : 'input-group',
8294 inputblock.cn.push({
8296 cls : 'input-group-addon',
8301 inputblock.cn.push(input);
8303 if(this.hasFeedback && !this.allowBlank){
8304 inputblock.cls += ' has-feedback';
8305 inputblock.cn.push(feedback);
8309 inputblock.cn.push({
8311 cls : 'input-group-addon',
8324 cls: 'form-hidden-field'
8332 Roo.log('multiple');
8340 cls: 'form-hidden-field'
8344 cls: 'select2-choices',
8348 cls: 'select2-search-field',
8361 cls: 'select2-container input-group',
8366 // cls: 'typeahead typeahead-long dropdown-menu',
8367 // style: 'display:none'
8372 if(!this.multiple && this.showToggleBtn){
8378 if (this.caret != false) {
8381 cls: 'fa fa-' + this.caret
8388 cls : 'input-group-addon btn dropdown-toggle',
8393 cls: 'combobox-clear',
8407 combobox.cls += ' select2-container-multi';
8410 if (align ==='left' && this.fieldLabel.length) {
8412 Roo.log("left and has label");
8418 cls : 'control-label col-sm-' + this.labelWidth,
8419 html : this.fieldLabel
8423 cls : "col-sm-" + (12 - this.labelWidth),
8430 } else if ( this.fieldLabel.length) {
8436 //cls : 'input-group-addon',
8437 html : this.fieldLabel
8447 Roo.log(" no label && no align");
8454 ['xs','sm','md','lg'].map(function(size){
8455 if (settings[size]) {
8456 cfg.cls += ' col-' + size + '-' + settings[size];
8467 onResize : function(w, h){
8468 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8469 // if(typeof w == 'number'){
8470 // var x = w - this.trigger.getWidth();
8471 // this.inputEl().setWidth(this.adjustWidth('input', x));
8472 // this.trigger.setStyle('left', x+'px');
8477 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8480 getResizeEl : function(){
8481 return this.inputEl();
8485 getPositionEl : function(){
8486 return this.inputEl();
8490 alignErrorIcon : function(){
8491 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8495 initEvents : function(){
8499 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8500 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8501 if(!this.multiple && this.showToggleBtn){
8502 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8503 if(this.hideTrigger){
8504 this.trigger.setDisplayed(false);
8506 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8510 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8513 //this.trigger.addClassOnOver('x-form-trigger-over');
8514 //this.trigger.addClassOnClick('x-form-trigger-click');
8517 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8521 createList : function()
8523 this.list = Roo.get(document.body).createChild({
8525 cls: 'typeahead typeahead-long dropdown-menu',
8526 style: 'display:none'
8529 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8534 initTrigger : function(){
8539 onDestroy : function(){
8541 this.trigger.removeAllListeners();
8542 // this.trigger.remove();
8545 // this.wrap.remove();
8547 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8551 onFocus : function(){
8552 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8555 this.wrap.addClass('x-trigger-wrap-focus');
8556 this.mimicing = true;
8557 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8558 if(this.monitorTab){
8559 this.el.on("keydown", this.checkTab, this);
8566 checkTab : function(e){
8567 if(e.getKey() == e.TAB){
8573 onBlur : function(){
8578 mimicBlur : function(e, t){
8580 if(!this.wrap.contains(t) && this.validateBlur()){
8587 triggerBlur : function(){
8588 this.mimicing = false;
8589 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8590 if(this.monitorTab){
8591 this.el.un("keydown", this.checkTab, this);
8593 //this.wrap.removeClass('x-trigger-wrap-focus');
8594 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8598 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8599 validateBlur : function(e, t){
8604 onDisable : function(){
8605 this.inputEl().dom.disabled = true;
8606 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8608 // this.wrap.addClass('x-item-disabled');
8613 onEnable : function(){
8614 this.inputEl().dom.disabled = false;
8615 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8617 // this.el.removeClass('x-item-disabled');
8622 onShow : function(){
8623 var ae = this.getActionEl();
8626 ae.dom.style.display = '';
8627 ae.dom.style.visibility = 'visible';
8633 onHide : function(){
8634 var ae = this.getActionEl();
8635 ae.dom.style.display = 'none';
8639 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8640 * by an implementing function.
8642 * @param {EventObject} e
8644 onTriggerClick : Roo.emptyFn
8648 * Ext JS Library 1.1.1
8649 * Copyright(c) 2006-2007, Ext JS, LLC.
8651 * Originally Released Under LGPL - original licence link has changed is not relivant.
8654 * <script type="text/javascript">
8659 * @class Roo.data.SortTypes
8661 * Defines the default sorting (casting?) comparison functions used when sorting data.
8663 Roo.data.SortTypes = {
8665 * Default sort that does nothing
8666 * @param {Mixed} s The value being converted
8667 * @return {Mixed} The comparison value
8674 * The regular expression used to strip tags
8678 stripTagsRE : /<\/?[^>]+>/gi,
8681 * Strips all HTML tags to sort on text only
8682 * @param {Mixed} s The value being converted
8683 * @return {String} The comparison value
8685 asText : function(s){
8686 return String(s).replace(this.stripTagsRE, "");
8690 * Strips all HTML tags to sort on text only - Case insensitive
8691 * @param {Mixed} s The value being converted
8692 * @return {String} The comparison value
8694 asUCText : function(s){
8695 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8699 * Case insensitive string
8700 * @param {Mixed} s The value being converted
8701 * @return {String} The comparison value
8703 asUCString : function(s) {
8704 return String(s).toUpperCase();
8709 * @param {Mixed} s The value being converted
8710 * @return {Number} The comparison value
8712 asDate : function(s) {
8716 if(s instanceof Date){
8719 return Date.parse(String(s));
8724 * @param {Mixed} s The value being converted
8725 * @return {Float} The comparison value
8727 asFloat : function(s) {
8728 var val = parseFloat(String(s).replace(/,/g, ""));
8729 if(isNaN(val)) val = 0;
8735 * @param {Mixed} s The value being converted
8736 * @return {Number} The comparison value
8738 asInt : function(s) {
8739 var val = parseInt(String(s).replace(/,/g, ""));
8740 if(isNaN(val)) val = 0;
8745 * Ext JS Library 1.1.1
8746 * Copyright(c) 2006-2007, Ext JS, LLC.
8748 * Originally Released Under LGPL - original licence link has changed is not relivant.
8751 * <script type="text/javascript">
8755 * @class Roo.data.Record
8756 * Instances of this class encapsulate both record <em>definition</em> information, and record
8757 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8758 * to access Records cached in an {@link Roo.data.Store} object.<br>
8760 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8761 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8764 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8766 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8767 * {@link #create}. The parameters are the same.
8768 * @param {Array} data An associative Array of data values keyed by the field name.
8769 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8770 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8771 * not specified an integer id is generated.
8773 Roo.data.Record = function(data, id){
8774 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8779 * Generate a constructor for a specific record layout.
8780 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8781 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8782 * Each field definition object may contain the following properties: <ul>
8783 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8784 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8785 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8786 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8787 * is being used, then this is a string containing the javascript expression to reference the data relative to
8788 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8789 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8790 * this may be omitted.</p></li>
8791 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8792 * <ul><li>auto (Default, implies no conversion)</li>
8797 * <li>date</li></ul></p></li>
8798 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8799 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8800 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8801 * by the Reader into an object that will be stored in the Record. It is passed the
8802 * following parameters:<ul>
8803 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8805 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8807 * <br>usage:<br><pre><code>
8808 var TopicRecord = Roo.data.Record.create(
8809 {name: 'title', mapping: 'topic_title'},
8810 {name: 'author', mapping: 'username'},
8811 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8812 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8813 {name: 'lastPoster', mapping: 'user2'},
8814 {name: 'excerpt', mapping: 'post_text'}
8817 var myNewRecord = new TopicRecord({
8818 title: 'Do my job please',
8821 lastPost: new Date(),
8822 lastPoster: 'Animal',
8823 excerpt: 'No way dude!'
8825 myStore.add(myNewRecord);
8830 Roo.data.Record.create = function(o){
8832 f.superclass.constructor.apply(this, arguments);
8834 Roo.extend(f, Roo.data.Record);
8835 var p = f.prototype;
8836 p.fields = new Roo.util.MixedCollection(false, function(field){
8839 for(var i = 0, len = o.length; i < len; i++){
8840 p.fields.add(new Roo.data.Field(o[i]));
8842 f.getField = function(name){
8843 return p.fields.get(name);
8848 Roo.data.Record.AUTO_ID = 1000;
8849 Roo.data.Record.EDIT = 'edit';
8850 Roo.data.Record.REJECT = 'reject';
8851 Roo.data.Record.COMMIT = 'commit';
8853 Roo.data.Record.prototype = {
8855 * Readonly flag - true if this record has been modified.
8864 join : function(store){
8869 * Set the named field to the specified value.
8870 * @param {String} name The name of the field to set.
8871 * @param {Object} value The value to set the field to.
8873 set : function(name, value){
8874 if(this.data[name] == value){
8881 if(typeof this.modified[name] == 'undefined'){
8882 this.modified[name] = this.data[name];
8884 this.data[name] = value;
8885 if(!this.editing && this.store){
8886 this.store.afterEdit(this);
8891 * Get the value of the named field.
8892 * @param {String} name The name of the field to get the value of.
8893 * @return {Object} The value of the field.
8895 get : function(name){
8896 return this.data[name];
8900 beginEdit : function(){
8901 this.editing = true;
8906 cancelEdit : function(){
8907 this.editing = false;
8908 delete this.modified;
8912 endEdit : function(){
8913 this.editing = false;
8914 if(this.dirty && this.store){
8915 this.store.afterEdit(this);
8920 * Usually called by the {@link Roo.data.Store} which owns the Record.
8921 * Rejects all changes made to the Record since either creation, or the last commit operation.
8922 * Modified fields are reverted to their original values.
8924 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8925 * of reject operations.
8927 reject : function(){
8928 var m = this.modified;
8930 if(typeof m[n] != "function"){
8931 this.data[n] = m[n];
8935 delete this.modified;
8936 this.editing = false;
8938 this.store.afterReject(this);
8943 * Usually called by the {@link Roo.data.Store} which owns the Record.
8944 * Commits all changes made to the Record since either creation, or the last commit operation.
8946 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8947 * of commit operations.
8949 commit : function(){
8951 delete this.modified;
8952 this.editing = false;
8954 this.store.afterCommit(this);
8959 hasError : function(){
8960 return this.error != null;
8964 clearError : function(){
8969 * Creates a copy of this record.
8970 * @param {String} id (optional) A new record id if you don't want to use this record's id
8973 copy : function(newId) {
8974 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8978 * Ext JS Library 1.1.1
8979 * Copyright(c) 2006-2007, Ext JS, LLC.
8981 * Originally Released Under LGPL - original licence link has changed is not relivant.
8984 * <script type="text/javascript">
8990 * @class Roo.data.Store
8991 * @extends Roo.util.Observable
8992 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8993 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8995 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8996 * has no knowledge of the format of the data returned by the Proxy.<br>
8998 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8999 * instances from the data object. These records are cached and made available through accessor functions.
9001 * Creates a new Store.
9002 * @param {Object} config A config object containing the objects needed for the Store to access data,
9003 * and read the data into Records.
9005 Roo.data.Store = function(config){
9006 this.data = new Roo.util.MixedCollection(false);
9007 this.data.getKey = function(o){
9010 this.baseParams = {};
9017 "multisort" : "_multisort"
9020 if(config && config.data){
9021 this.inlineData = config.data;
9025 Roo.apply(this, config);
9027 if(this.reader){ // reader passed
9028 this.reader = Roo.factory(this.reader, Roo.data);
9029 this.reader.xmodule = this.xmodule || false;
9030 if(!this.recordType){
9031 this.recordType = this.reader.recordType;
9033 if(this.reader.onMetaChange){
9034 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9038 if(this.recordType){
9039 this.fields = this.recordType.prototype.fields;
9045 * @event datachanged
9046 * Fires when the data cache has changed, and a widget which is using this Store
9047 * as a Record cache should refresh its view.
9048 * @param {Store} this
9053 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9054 * @param {Store} this
9055 * @param {Object} meta The JSON metadata
9060 * Fires when Records have been added to the Store
9061 * @param {Store} this
9062 * @param {Roo.data.Record[]} records The array of Records added
9063 * @param {Number} index The index at which the record(s) were added
9068 * Fires when a Record has been removed from the Store
9069 * @param {Store} this
9070 * @param {Roo.data.Record} record The Record that was removed
9071 * @param {Number} index The index at which the record was removed
9076 * Fires when a Record has been updated
9077 * @param {Store} this
9078 * @param {Roo.data.Record} record The Record that was updated
9079 * @param {String} operation The update operation being performed. Value may be one of:
9081 Roo.data.Record.EDIT
9082 Roo.data.Record.REJECT
9083 Roo.data.Record.COMMIT
9089 * Fires when the data cache has been cleared.
9090 * @param {Store} this
9095 * Fires before a request is made for a new data object. If the beforeload handler returns false
9096 * the load action will be canceled.
9097 * @param {Store} this
9098 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9102 * @event beforeloadadd
9103 * Fires after a new set of Records has been loaded.
9104 * @param {Store} this
9105 * @param {Roo.data.Record[]} records The Records that were loaded
9106 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9108 beforeloadadd : true,
9111 * Fires after a new set of Records has been loaded, before they are added to the store.
9112 * @param {Store} this
9113 * @param {Roo.data.Record[]} records The Records that were loaded
9114 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9115 * @params {Object} return from reader
9119 * @event loadexception
9120 * Fires if an exception occurs in the Proxy during loading.
9121 * Called with the signature of the Proxy's "loadexception" event.
9122 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9125 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9126 * @param {Object} load options
9127 * @param {Object} jsonData from your request (normally this contains the Exception)
9129 loadexception : true
9133 this.proxy = Roo.factory(this.proxy, Roo.data);
9134 this.proxy.xmodule = this.xmodule || false;
9135 this.relayEvents(this.proxy, ["loadexception"]);
9137 this.sortToggle = {};
9138 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9140 Roo.data.Store.superclass.constructor.call(this);
9142 if(this.inlineData){
9143 this.loadData(this.inlineData);
9144 delete this.inlineData;
9148 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9150 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9151 * without a remote query - used by combo/forms at present.
9155 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9158 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9161 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9162 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9165 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9166 * on any HTTP request
9169 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9172 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9176 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9177 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9182 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9183 * loaded or when a record is removed. (defaults to false).
9185 pruneModifiedRecords : false,
9191 * Add Records to the Store and fires the add event.
9192 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9194 add : function(records){
9195 records = [].concat(records);
9196 for(var i = 0, len = records.length; i < len; i++){
9197 records[i].join(this);
9199 var index = this.data.length;
9200 this.data.addAll(records);
9201 this.fireEvent("add", this, records, index);
9205 * Remove a Record from the Store and fires the remove event.
9206 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9208 remove : function(record){
9209 var index = this.data.indexOf(record);
9210 this.data.removeAt(index);
9211 if(this.pruneModifiedRecords){
9212 this.modified.remove(record);
9214 this.fireEvent("remove", this, record, index);
9218 * Remove all Records from the Store and fires the clear event.
9220 removeAll : function(){
9222 if(this.pruneModifiedRecords){
9225 this.fireEvent("clear", this);
9229 * Inserts Records to the Store at the given index and fires the add event.
9230 * @param {Number} index The start index at which to insert the passed Records.
9231 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9233 insert : function(index, records){
9234 records = [].concat(records);
9235 for(var i = 0, len = records.length; i < len; i++){
9236 this.data.insert(index, records[i]);
9237 records[i].join(this);
9239 this.fireEvent("add", this, records, index);
9243 * Get the index within the cache of the passed Record.
9244 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9245 * @return {Number} The index of the passed Record. Returns -1 if not found.
9247 indexOf : function(record){
9248 return this.data.indexOf(record);
9252 * Get the index within the cache of the Record with the passed id.
9253 * @param {String} id The id of the Record to find.
9254 * @return {Number} The index of the Record. Returns -1 if not found.
9256 indexOfId : function(id){
9257 return this.data.indexOfKey(id);
9261 * Get the Record with the specified id.
9262 * @param {String} id The id of the Record to find.
9263 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9265 getById : function(id){
9266 return this.data.key(id);
9270 * Get the Record at the specified index.
9271 * @param {Number} index The index of the Record to find.
9272 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9274 getAt : function(index){
9275 return this.data.itemAt(index);
9279 * Returns a range of Records between specified indices.
9280 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9281 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9282 * @return {Roo.data.Record[]} An array of Records
9284 getRange : function(start, end){
9285 return this.data.getRange(start, end);
9289 storeOptions : function(o){
9290 o = Roo.apply({}, o);
9293 this.lastOptions = o;
9297 * Loads the Record cache from the configured Proxy using the configured Reader.
9299 * If using remote paging, then the first load call must specify the <em>start</em>
9300 * and <em>limit</em> properties in the options.params property to establish the initial
9301 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9303 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9304 * and this call will return before the new data has been loaded. Perform any post-processing
9305 * in a callback function, or in a "load" event handler.</strong>
9307 * @param {Object} options An object containing properties which control loading options:<ul>
9308 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9309 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9310 * passed the following arguments:<ul>
9311 * <li>r : Roo.data.Record[]</li>
9312 * <li>options: Options object from the load call</li>
9313 * <li>success: Boolean success indicator</li></ul></li>
9314 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9315 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9318 load : function(options){
9319 options = options || {};
9320 if(this.fireEvent("beforeload", this, options) !== false){
9321 this.storeOptions(options);
9322 var p = Roo.apply(options.params || {}, this.baseParams);
9323 // if meta was not loaded from remote source.. try requesting it.
9324 if (!this.reader.metaFromRemote) {
9327 if(this.sortInfo && this.remoteSort){
9328 var pn = this.paramNames;
9329 p[pn["sort"]] = this.sortInfo.field;
9330 p[pn["dir"]] = this.sortInfo.direction;
9332 if (this.multiSort) {
9333 var pn = this.paramNames;
9334 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9337 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9342 * Reloads the Record cache from the configured Proxy using the configured Reader and
9343 * the options from the last load operation performed.
9344 * @param {Object} options (optional) An object containing properties which may override the options
9345 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9346 * the most recently used options are reused).
9348 reload : function(options){
9349 this.load(Roo.applyIf(options||{}, this.lastOptions));
9353 // Called as a callback by the Reader during a load operation.
9354 loadRecords : function(o, options, success){
9355 if(!o || success === false){
9356 if(success !== false){
9357 this.fireEvent("load", this, [], options, o);
9359 if(options.callback){
9360 options.callback.call(options.scope || this, [], options, false);
9364 // if data returned failure - throw an exception.
9365 if (o.success === false) {
9366 // show a message if no listener is registered.
9367 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9368 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9370 // loadmask wil be hooked into this..
9371 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9374 var r = o.records, t = o.totalRecords || r.length;
9376 this.fireEvent("beforeloadadd", this, r, options, o);
9378 if(!options || options.add !== true){
9379 if(this.pruneModifiedRecords){
9382 for(var i = 0, len = r.length; i < len; i++){
9386 this.data = this.snapshot;
9387 delete this.snapshot;
9390 this.data.addAll(r);
9391 this.totalLength = t;
9393 this.fireEvent("datachanged", this);
9395 this.totalLength = Math.max(t, this.data.length+r.length);
9398 this.fireEvent("load", this, r, options, o);
9399 if(options.callback){
9400 options.callback.call(options.scope || this, r, options, true);
9406 * Loads data from a passed data block. A Reader which understands the format of the data
9407 * must have been configured in the constructor.
9408 * @param {Object} data The data block from which to read the Records. The format of the data expected
9409 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9410 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9412 loadData : function(o, append){
9413 var r = this.reader.readRecords(o);
9414 this.loadRecords(r, {add: append}, true);
9418 * Gets the number of cached records.
9420 * <em>If using paging, this may not be the total size of the dataset. If the data object
9421 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9422 * the data set size</em>
9424 getCount : function(){
9425 return this.data.length || 0;
9429 * Gets the total number of records in the dataset as returned by the server.
9431 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9432 * the dataset size</em>
9434 getTotalCount : function(){
9435 return this.totalLength || 0;
9439 * Returns the sort state of the Store as an object with two properties:
9441 field {String} The name of the field by which the Records are sorted
9442 direction {String} The sort order, "ASC" or "DESC"
9445 getSortState : function(){
9446 return this.sortInfo;
9450 applySort : function(){
9451 if(this.sortInfo && !this.remoteSort){
9452 var s = this.sortInfo, f = s.field;
9453 var st = this.fields.get(f).sortType;
9454 var fn = function(r1, r2){
9455 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9456 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9458 this.data.sort(s.direction, fn);
9459 if(this.snapshot && this.snapshot != this.data){
9460 this.snapshot.sort(s.direction, fn);
9466 * Sets the default sort column and order to be used by the next load operation.
9467 * @param {String} fieldName The name of the field to sort by.
9468 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9470 setDefaultSort : function(field, dir){
9471 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9476 * If remote sorting is used, the sort is performed on the server, and the cache is
9477 * reloaded. If local sorting is used, the cache is sorted internally.
9478 * @param {String} fieldName The name of the field to sort by.
9479 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9481 sort : function(fieldName, dir){
9482 var f = this.fields.get(fieldName);
9484 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9486 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9487 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9492 this.sortToggle[f.name] = dir;
9493 this.sortInfo = {field: f.name, direction: dir};
9494 if(!this.remoteSort){
9496 this.fireEvent("datachanged", this);
9498 this.load(this.lastOptions);
9503 * Calls the specified function for each of the Records in the cache.
9504 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9505 * Returning <em>false</em> aborts and exits the iteration.
9506 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9508 each : function(fn, scope){
9509 this.data.each(fn, scope);
9513 * Gets all records modified since the last commit. Modified records are persisted across load operations
9514 * (e.g., during paging).
9515 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9517 getModifiedRecords : function(){
9518 return this.modified;
9522 createFilterFn : function(property, value, anyMatch){
9523 if(!value.exec){ // not a regex
9524 value = String(value);
9525 if(value.length == 0){
9528 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9531 return value.test(r.data[property]);
9536 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9537 * @param {String} property A field on your records
9538 * @param {Number} start The record index to start at (defaults to 0)
9539 * @param {Number} end The last record index to include (defaults to length - 1)
9540 * @return {Number} The sum
9542 sum : function(property, start, end){
9543 var rs = this.data.items, v = 0;
9545 end = (end || end === 0) ? end : rs.length-1;
9547 for(var i = start; i <= end; i++){
9548 v += (rs[i].data[property] || 0);
9554 * Filter the records by a specified property.
9555 * @param {String} field A field on your records
9556 * @param {String/RegExp} value Either a string that the field
9557 * should start with or a RegExp to test against the field
9558 * @param {Boolean} anyMatch True to match any part not just the beginning
9560 filter : function(property, value, anyMatch){
9561 var fn = this.createFilterFn(property, value, anyMatch);
9562 return fn ? this.filterBy(fn) : this.clearFilter();
9566 * Filter by a function. The specified function will be called with each
9567 * record in this data source. If the function returns true the record is included,
9568 * otherwise it is filtered.
9569 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9570 * @param {Object} scope (optional) The scope of the function (defaults to this)
9572 filterBy : function(fn, scope){
9573 this.snapshot = this.snapshot || this.data;
9574 this.data = this.queryBy(fn, scope||this);
9575 this.fireEvent("datachanged", this);
9579 * Query the records by a specified property.
9580 * @param {String} field A field on your records
9581 * @param {String/RegExp} value Either a string that the field
9582 * should start with or a RegExp to test against the field
9583 * @param {Boolean} anyMatch True to match any part not just the beginning
9584 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9586 query : function(property, value, anyMatch){
9587 var fn = this.createFilterFn(property, value, anyMatch);
9588 return fn ? this.queryBy(fn) : this.data.clone();
9592 * Query by a function. The specified function will be called with each
9593 * record in this data source. If the function returns true the record is included
9595 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9596 * @param {Object} scope (optional) The scope of the function (defaults to this)
9597 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9599 queryBy : function(fn, scope){
9600 var data = this.snapshot || this.data;
9601 return data.filterBy(fn, scope||this);
9605 * Collects unique values for a particular dataIndex from this store.
9606 * @param {String} dataIndex The property to collect
9607 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9608 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9609 * @return {Array} An array of the unique values
9611 collect : function(dataIndex, allowNull, bypassFilter){
9612 var d = (bypassFilter === true && this.snapshot) ?
9613 this.snapshot.items : this.data.items;
9614 var v, sv, r = [], l = {};
9615 for(var i = 0, len = d.length; i < len; i++){
9616 v = d[i].data[dataIndex];
9618 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9627 * Revert to a view of the Record cache with no filtering applied.
9628 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9630 clearFilter : function(suppressEvent){
9631 if(this.snapshot && this.snapshot != this.data){
9632 this.data = this.snapshot;
9633 delete this.snapshot;
9634 if(suppressEvent !== true){
9635 this.fireEvent("datachanged", this);
9641 afterEdit : function(record){
9642 if(this.modified.indexOf(record) == -1){
9643 this.modified.push(record);
9645 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9649 afterReject : function(record){
9650 this.modified.remove(record);
9651 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9655 afterCommit : function(record){
9656 this.modified.remove(record);
9657 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9661 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9662 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9664 commitChanges : function(){
9665 var m = this.modified.slice(0);
9667 for(var i = 0, len = m.length; i < len; i++){
9673 * Cancel outstanding changes on all changed records.
9675 rejectChanges : function(){
9676 var m = this.modified.slice(0);
9678 for(var i = 0, len = m.length; i < len; i++){
9683 onMetaChange : function(meta, rtype, o){
9684 this.recordType = rtype;
9685 this.fields = rtype.prototype.fields;
9686 delete this.snapshot;
9687 this.sortInfo = meta.sortInfo || this.sortInfo;
9689 this.fireEvent('metachange', this, this.reader.meta);
9692 moveIndex : function(data, type)
9694 var index = this.indexOf(data);
9696 var newIndex = index + type;
9700 this.insert(newIndex, data);
9705 * Ext JS Library 1.1.1
9706 * Copyright(c) 2006-2007, Ext JS, LLC.
9708 * Originally Released Under LGPL - original licence link has changed is not relivant.
9711 * <script type="text/javascript">
9715 * @class Roo.data.SimpleStore
9716 * @extends Roo.data.Store
9717 * Small helper class to make creating Stores from Array data easier.
9718 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9719 * @cfg {Array} fields An array of field definition objects, or field name strings.
9720 * @cfg {Array} data The multi-dimensional array of data
9722 * @param {Object} config
9724 Roo.data.SimpleStore = function(config){
9725 Roo.data.SimpleStore.superclass.constructor.call(this, {
9727 reader: new Roo.data.ArrayReader({
9730 Roo.data.Record.create(config.fields)
9732 proxy : new Roo.data.MemoryProxy(config.data)
9736 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9738 * Ext JS Library 1.1.1
9739 * Copyright(c) 2006-2007, Ext JS, LLC.
9741 * Originally Released Under LGPL - original licence link has changed is not relivant.
9744 * <script type="text/javascript">
9749 * @extends Roo.data.Store
9750 * @class Roo.data.JsonStore
9751 * Small helper class to make creating Stores for JSON data easier. <br/>
9753 var store = new Roo.data.JsonStore({
9754 url: 'get-images.php',
9756 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9759 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9760 * JsonReader and HttpProxy (unless inline data is provided).</b>
9761 * @cfg {Array} fields An array of field definition objects, or field name strings.
9763 * @param {Object} config
9765 Roo.data.JsonStore = function(c){
9766 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9767 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9768 reader: new Roo.data.JsonReader(c, c.fields)
9771 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9773 * Ext JS Library 1.1.1
9774 * Copyright(c) 2006-2007, Ext JS, LLC.
9776 * Originally Released Under LGPL - original licence link has changed is not relivant.
9779 * <script type="text/javascript">
9783 Roo.data.Field = function(config){
9784 if(typeof config == "string"){
9785 config = {name: config};
9787 Roo.apply(this, config);
9793 var st = Roo.data.SortTypes;
9794 // named sortTypes are supported, here we look them up
9795 if(typeof this.sortType == "string"){
9796 this.sortType = st[this.sortType];
9799 // set default sortType for strings and dates
9803 this.sortType = st.asUCString;
9806 this.sortType = st.asDate;
9809 this.sortType = st.none;
9814 var stripRe = /[\$,%]/g;
9816 // prebuilt conversion function for this field, instead of
9817 // switching every time we're reading a value
9819 var cv, dateFormat = this.dateFormat;
9824 cv = function(v){ return v; };
9827 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9831 return v !== undefined && v !== null && v !== '' ?
9832 parseInt(String(v).replace(stripRe, ""), 10) : '';
9837 return v !== undefined && v !== null && v !== '' ?
9838 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9843 cv = function(v){ return v === true || v === "true" || v == 1; };
9850 if(v instanceof Date){
9854 if(dateFormat == "timestamp"){
9855 return new Date(v*1000);
9857 return Date.parseDate(v, dateFormat);
9859 var parsed = Date.parse(v);
9860 return parsed ? new Date(parsed) : null;
9869 Roo.data.Field.prototype = {
9877 * Ext JS Library 1.1.1
9878 * Copyright(c) 2006-2007, Ext JS, LLC.
9880 * Originally Released Under LGPL - original licence link has changed is not relivant.
9883 * <script type="text/javascript">
9886 // Base class for reading structured data from a data source. This class is intended to be
9887 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9890 * @class Roo.data.DataReader
9891 * Base class for reading structured data from a data source. This class is intended to be
9892 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9895 Roo.data.DataReader = function(meta, recordType){
9899 this.recordType = recordType instanceof Array ?
9900 Roo.data.Record.create(recordType) : recordType;
9903 Roo.data.DataReader.prototype = {
9905 * Create an empty record
9906 * @param {Object} data (optional) - overlay some values
9907 * @return {Roo.data.Record} record created.
9909 newRow : function(d) {
9911 this.recordType.prototype.fields.each(function(c) {
9913 case 'int' : da[c.name] = 0; break;
9914 case 'date' : da[c.name] = new Date(); break;
9915 case 'float' : da[c.name] = 0.0; break;
9916 case 'boolean' : da[c.name] = false; break;
9917 default : da[c.name] = ""; break;
9921 return new this.recordType(Roo.apply(da, d));
9926 * Ext JS Library 1.1.1
9927 * Copyright(c) 2006-2007, Ext JS, LLC.
9929 * Originally Released Under LGPL - original licence link has changed is not relivant.
9932 * <script type="text/javascript">
9936 * @class Roo.data.DataProxy
9937 * @extends Roo.data.Observable
9938 * This class is an abstract base class for implementations which provide retrieval of
9939 * unformatted data objects.<br>
9941 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9942 * (of the appropriate type which knows how to parse the data object) to provide a block of
9943 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9945 * Custom implementations must implement the load method as described in
9946 * {@link Roo.data.HttpProxy#load}.
9948 Roo.data.DataProxy = function(){
9952 * Fires before a network request is made to retrieve a data object.
9953 * @param {Object} This DataProxy object.
9954 * @param {Object} params The params parameter to the load function.
9959 * Fires before the load method's callback is called.
9960 * @param {Object} This DataProxy object.
9961 * @param {Object} o The data object.
9962 * @param {Object} arg The callback argument object passed to the load function.
9966 * @event loadexception
9967 * Fires if an Exception occurs during data retrieval.
9968 * @param {Object} This DataProxy object.
9969 * @param {Object} o The data object.
9970 * @param {Object} arg The callback argument object passed to the load function.
9971 * @param {Object} e The Exception.
9973 loadexception : true
9975 Roo.data.DataProxy.superclass.constructor.call(this);
9978 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9981 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9985 * Ext JS Library 1.1.1
9986 * Copyright(c) 2006-2007, Ext JS, LLC.
9988 * Originally Released Under LGPL - original licence link has changed is not relivant.
9991 * <script type="text/javascript">
9994 * @class Roo.data.MemoryProxy
9995 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9996 * to the Reader when its load method is called.
9998 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10000 Roo.data.MemoryProxy = function(data){
10004 Roo.data.MemoryProxy.superclass.constructor.call(this);
10008 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10010 * Load data from the requested source (in this case an in-memory
10011 * data object passed to the constructor), read the data object into
10012 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10013 * process that block using the passed callback.
10014 * @param {Object} params This parameter is not used by the MemoryProxy class.
10015 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10016 * object into a block of Roo.data.Records.
10017 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10018 * The function must be passed <ul>
10019 * <li>The Record block object</li>
10020 * <li>The "arg" argument from the load function</li>
10021 * <li>A boolean success indicator</li>
10023 * @param {Object} scope The scope in which to call the callback
10024 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10026 load : function(params, reader, callback, scope, arg){
10027 params = params || {};
10030 result = reader.readRecords(this.data);
10032 this.fireEvent("loadexception", this, arg, null, e);
10033 callback.call(scope, null, arg, false);
10036 callback.call(scope, result, arg, true);
10040 update : function(params, records){
10045 * Ext JS Library 1.1.1
10046 * Copyright(c) 2006-2007, Ext JS, LLC.
10048 * Originally Released Under LGPL - original licence link has changed is not relivant.
10051 * <script type="text/javascript">
10054 * @class Roo.data.HttpProxy
10055 * @extends Roo.data.DataProxy
10056 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10057 * configured to reference a certain URL.<br><br>
10059 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10060 * from which the running page was served.<br><br>
10062 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10064 * Be aware that to enable the browser to parse an XML document, the server must set
10065 * the Content-Type header in the HTTP response to "text/xml".
10067 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10068 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10069 * will be used to make the request.
10071 Roo.data.HttpProxy = function(conn){
10072 Roo.data.HttpProxy.superclass.constructor.call(this);
10073 // is conn a conn config or a real conn?
10075 this.useAjax = !conn || !conn.events;
10079 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10080 // thse are take from connection...
10083 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10086 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10087 * extra parameters to each request made by this object. (defaults to undefined)
10090 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10091 * to each request made by this object. (defaults to undefined)
10094 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
10097 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10100 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10106 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10110 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10111 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10112 * a finer-grained basis than the DataProxy events.
10114 getConnection : function(){
10115 return this.useAjax ? Roo.Ajax : this.conn;
10119 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10120 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10121 * process that block using the passed callback.
10122 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10123 * for the request to the remote server.
10124 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10125 * object into a block of Roo.data.Records.
10126 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10127 * The function must be passed <ul>
10128 * <li>The Record block object</li>
10129 * <li>The "arg" argument from the load function</li>
10130 * <li>A boolean success indicator</li>
10132 * @param {Object} scope The scope in which to call the callback
10133 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10135 load : function(params, reader, callback, scope, arg){
10136 if(this.fireEvent("beforeload", this, params) !== false){
10138 params : params || {},
10140 callback : callback,
10145 callback : this.loadResponse,
10149 Roo.applyIf(o, this.conn);
10150 if(this.activeRequest){
10151 Roo.Ajax.abort(this.activeRequest);
10153 this.activeRequest = Roo.Ajax.request(o);
10155 this.conn.request(o);
10158 callback.call(scope||this, null, arg, false);
10163 loadResponse : function(o, success, response){
10164 delete this.activeRequest;
10166 this.fireEvent("loadexception", this, o, response);
10167 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10172 result = o.reader.read(response);
10174 this.fireEvent("loadexception", this, o, response, e);
10175 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10179 this.fireEvent("load", this, o, o.request.arg);
10180 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10184 update : function(dataSet){
10189 updateResponse : function(dataSet){
10194 * Ext JS Library 1.1.1
10195 * Copyright(c) 2006-2007, Ext JS, LLC.
10197 * Originally Released Under LGPL - original licence link has changed is not relivant.
10200 * <script type="text/javascript">
10204 * @class Roo.data.ScriptTagProxy
10205 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10206 * other than the originating domain of the running page.<br><br>
10208 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
10209 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10211 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10212 * source code that is used as the source inside a <script> tag.<br><br>
10214 * In order for the browser to process the returned data, the server must wrap the data object
10215 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10216 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10217 * depending on whether the callback name was passed:
10220 boolean scriptTag = false;
10221 String cb = request.getParameter("callback");
10224 response.setContentType("text/javascript");
10226 response.setContentType("application/x-json");
10228 Writer out = response.getWriter();
10230 out.write(cb + "(");
10232 out.print(dataBlock.toJsonString());
10239 * @param {Object} config A configuration object.
10241 Roo.data.ScriptTagProxy = function(config){
10242 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10243 Roo.apply(this, config);
10244 this.head = document.getElementsByTagName("head")[0];
10247 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10249 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10251 * @cfg {String} url The URL from which to request the data object.
10254 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10258 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10259 * the server the name of the callback function set up by the load call to process the returned data object.
10260 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10261 * javascript output which calls this named function passing the data object as its only parameter.
10263 callbackParam : "callback",
10265 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10266 * name to the request.
10271 * Load data from the configured URL, read the data object into
10272 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10273 * process that block using the passed callback.
10274 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10275 * for the request to the remote server.
10276 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10277 * object into a block of Roo.data.Records.
10278 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10279 * The function must be passed <ul>
10280 * <li>The Record block object</li>
10281 * <li>The "arg" argument from the load function</li>
10282 * <li>A boolean success indicator</li>
10284 * @param {Object} scope The scope in which to call the callback
10285 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10287 load : function(params, reader, callback, scope, arg){
10288 if(this.fireEvent("beforeload", this, params) !== false){
10290 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10292 var url = this.url;
10293 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10295 url += "&_dc=" + (new Date().getTime());
10297 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10300 cb : "stcCallback"+transId,
10301 scriptId : "stcScript"+transId,
10305 callback : callback,
10311 window[trans.cb] = function(o){
10312 conn.handleResponse(o, trans);
10315 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10317 if(this.autoAbort !== false){
10321 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10323 var script = document.createElement("script");
10324 script.setAttribute("src", url);
10325 script.setAttribute("type", "text/javascript");
10326 script.setAttribute("id", trans.scriptId);
10327 this.head.appendChild(script);
10329 this.trans = trans;
10331 callback.call(scope||this, null, arg, false);
10336 isLoading : function(){
10337 return this.trans ? true : false;
10341 * Abort the current server request.
10343 abort : function(){
10344 if(this.isLoading()){
10345 this.destroyTrans(this.trans);
10350 destroyTrans : function(trans, isLoaded){
10351 this.head.removeChild(document.getElementById(trans.scriptId));
10352 clearTimeout(trans.timeoutId);
10354 window[trans.cb] = undefined;
10356 delete window[trans.cb];
10359 // if hasn't been loaded, wait for load to remove it to prevent script error
10360 window[trans.cb] = function(){
10361 window[trans.cb] = undefined;
10363 delete window[trans.cb];
10370 handleResponse : function(o, trans){
10371 this.trans = false;
10372 this.destroyTrans(trans, true);
10375 result = trans.reader.readRecords(o);
10377 this.fireEvent("loadexception", this, o, trans.arg, e);
10378 trans.callback.call(trans.scope||window, null, trans.arg, false);
10381 this.fireEvent("load", this, o, trans.arg);
10382 trans.callback.call(trans.scope||window, result, trans.arg, true);
10386 handleFailure : function(trans){
10387 this.trans = false;
10388 this.destroyTrans(trans, false);
10389 this.fireEvent("loadexception", this, null, trans.arg);
10390 trans.callback.call(trans.scope||window, null, trans.arg, false);
10394 * Ext JS Library 1.1.1
10395 * Copyright(c) 2006-2007, Ext JS, LLC.
10397 * Originally Released Under LGPL - original licence link has changed is not relivant.
10400 * <script type="text/javascript">
10404 * @class Roo.data.JsonReader
10405 * @extends Roo.data.DataReader
10406 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10407 * based on mappings in a provided Roo.data.Record constructor.
10409 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10410 * in the reply previously.
10415 var RecordDef = Roo.data.Record.create([
10416 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10417 {name: 'occupation'} // This field will use "occupation" as the mapping.
10419 var myReader = new Roo.data.JsonReader({
10420 totalProperty: "results", // The property which contains the total dataset size (optional)
10421 root: "rows", // The property which contains an Array of row objects
10422 id: "id" // The property within each row object that provides an ID for the record (optional)
10426 * This would consume a JSON file like this:
10428 { 'results': 2, 'rows': [
10429 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10430 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10433 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10434 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10435 * paged from the remote server.
10436 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10437 * @cfg {String} root name of the property which contains the Array of row objects.
10438 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10440 * Create a new JsonReader
10441 * @param {Object} meta Metadata configuration options
10442 * @param {Object} recordType Either an Array of field definition objects,
10443 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10445 Roo.data.JsonReader = function(meta, recordType){
10448 // set some defaults:
10449 Roo.applyIf(meta, {
10450 totalProperty: 'total',
10451 successProperty : 'success',
10456 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10458 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10461 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10462 * Used by Store query builder to append _requestMeta to params.
10465 metaFromRemote : false,
10467 * This method is only used by a DataProxy which has retrieved data from a remote server.
10468 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10469 * @return {Object} data A data block which is used by an Roo.data.Store object as
10470 * a cache of Roo.data.Records.
10472 read : function(response){
10473 var json = response.responseText;
10475 var o = /* eval:var:o */ eval("("+json+")");
10477 throw {message: "JsonReader.read: Json object not found"};
10483 this.metaFromRemote = true;
10484 this.meta = o.metaData;
10485 this.recordType = Roo.data.Record.create(o.metaData.fields);
10486 this.onMetaChange(this.meta, this.recordType, o);
10488 return this.readRecords(o);
10491 // private function a store will implement
10492 onMetaChange : function(meta, recordType, o){
10499 simpleAccess: function(obj, subsc) {
10506 getJsonAccessor: function(){
10508 return function(expr) {
10510 return(re.test(expr))
10511 ? new Function("obj", "return obj." + expr)
10516 return Roo.emptyFn;
10521 * Create a data block containing Roo.data.Records from an XML document.
10522 * @param {Object} o An object which contains an Array of row objects in the property specified
10523 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10524 * which contains the total size of the dataset.
10525 * @return {Object} data A data block which is used by an Roo.data.Store object as
10526 * a cache of Roo.data.Records.
10528 readRecords : function(o){
10530 * After any data loads, the raw JSON data is available for further custom processing.
10534 var s = this.meta, Record = this.recordType,
10535 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10537 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10539 if(s.totalProperty) {
10540 this.getTotal = this.getJsonAccessor(s.totalProperty);
10542 if(s.successProperty) {
10543 this.getSuccess = this.getJsonAccessor(s.successProperty);
10545 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10547 var g = this.getJsonAccessor(s.id);
10548 this.getId = function(rec) {
10550 return (r === undefined || r === "") ? null : r;
10553 this.getId = function(){return null;};
10556 for(var jj = 0; jj < fl; jj++){
10558 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10559 this.ef[jj] = this.getJsonAccessor(map);
10563 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10564 if(s.totalProperty){
10565 var vt = parseInt(this.getTotal(o), 10);
10570 if(s.successProperty){
10571 var vs = this.getSuccess(o);
10572 if(vs === false || vs === 'false'){
10577 for(var i = 0; i < c; i++){
10580 var id = this.getId(n);
10581 for(var j = 0; j < fl; j++){
10583 var v = this.ef[j](n);
10585 Roo.log('missing convert for ' + f.name);
10589 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10591 var record = new Record(values, id);
10593 records[i] = record;
10599 totalRecords : totalRecords
10604 * Ext JS Library 1.1.1
10605 * Copyright(c) 2006-2007, Ext JS, LLC.
10607 * Originally Released Under LGPL - original licence link has changed is not relivant.
10610 * <script type="text/javascript">
10614 * @class Roo.data.ArrayReader
10615 * @extends Roo.data.DataReader
10616 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10617 * Each element of that Array represents a row of data fields. The
10618 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10619 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10623 var RecordDef = Roo.data.Record.create([
10624 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10625 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10627 var myReader = new Roo.data.ArrayReader({
10628 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10632 * This would consume an Array like this:
10634 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10636 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10638 * Create a new JsonReader
10639 * @param {Object} meta Metadata configuration options.
10640 * @param {Object} recordType Either an Array of field definition objects
10641 * as specified to {@link Roo.data.Record#create},
10642 * or an {@link Roo.data.Record} object
10643 * created using {@link Roo.data.Record#create}.
10645 Roo.data.ArrayReader = function(meta, recordType){
10646 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10649 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10651 * Create a data block containing Roo.data.Records from an XML document.
10652 * @param {Object} o An Array of row objects which represents the dataset.
10653 * @return {Object} data A data block which is used by an Roo.data.Store object as
10654 * a cache of Roo.data.Records.
10656 readRecords : function(o){
10657 var sid = this.meta ? this.meta.id : null;
10658 var recordType = this.recordType, fields = recordType.prototype.fields;
10661 for(var i = 0; i < root.length; i++){
10664 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10665 for(var j = 0, jlen = fields.length; j < jlen; j++){
10666 var f = fields.items[j];
10667 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10668 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10670 values[f.name] = v;
10672 var record = new recordType(values, id);
10674 records[records.length] = record;
10678 totalRecords : records.length
10687 * @class Roo.bootstrap.ComboBox
10688 * @extends Roo.bootstrap.TriggerField
10689 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10690 * @cfg {Boolean} append (true|false) default false
10691 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10692 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10693 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10694 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10695 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10697 * Create a new ComboBox.
10698 * @param {Object} config Configuration options
10700 Roo.bootstrap.ComboBox = function(config){
10701 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10705 * Fires when the dropdown list is expanded
10706 * @param {Roo.bootstrap.ComboBox} combo This combo box
10711 * Fires when the dropdown list is collapsed
10712 * @param {Roo.bootstrap.ComboBox} combo This combo box
10716 * @event beforeselect
10717 * Fires before a list item is selected. Return false to cancel the selection.
10718 * @param {Roo.bootstrap.ComboBox} combo This combo box
10719 * @param {Roo.data.Record} record The data record returned from the underlying store
10720 * @param {Number} index The index of the selected item in the dropdown list
10722 'beforeselect' : true,
10725 * Fires when a list item is selected
10726 * @param {Roo.bootstrap.ComboBox} combo This combo box
10727 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10728 * @param {Number} index The index of the selected item in the dropdown list
10732 * @event beforequery
10733 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10734 * The event object passed has these properties:
10735 * @param {Roo.bootstrap.ComboBox} combo This combo box
10736 * @param {String} query The query
10737 * @param {Boolean} forceAll true to force "all" query
10738 * @param {Boolean} cancel true to cancel the query
10739 * @param {Object} e The query event object
10741 'beforequery': true,
10744 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10745 * @param {Roo.bootstrap.ComboBox} combo This combo box
10750 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10751 * @param {Roo.bootstrap.ComboBox} combo This combo box
10752 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10757 * Fires when the remove value from the combobox array
10758 * @param {Roo.bootstrap.ComboBox} combo This combo box
10762 * @event specialfilter
10763 * Fires when specialfilter
10764 * @param {Roo.bootstrap.ComboBox} combo This combo box
10766 'specialfilter' : true
10771 this.tickItems = [];
10773 this.selectedIndex = -1;
10774 if(this.mode == 'local'){
10775 if(config.queryDelay === undefined){
10776 this.queryDelay = 10;
10778 if(config.minChars === undefined){
10784 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10787 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10788 * rendering into an Roo.Editor, defaults to false)
10791 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10792 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10795 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10798 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10799 * the dropdown list (defaults to undefined, with no header element)
10803 * @cfg {String/Roo.Template} tpl The template to use to render the output
10807 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10809 listWidth: undefined,
10811 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10812 * mode = 'remote' or 'text' if mode = 'local')
10814 displayField: undefined,
10817 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10818 * mode = 'remote' or 'value' if mode = 'local').
10819 * Note: use of a valueField requires the user make a selection
10820 * in order for a value to be mapped.
10822 valueField: undefined,
10826 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10827 * field's data value (defaults to the underlying DOM element's name)
10829 hiddenName: undefined,
10831 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10835 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10837 selectedClass: 'active',
10840 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10844 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10845 * anchor positions (defaults to 'tl-bl')
10847 listAlign: 'tl-bl?',
10849 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10853 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10854 * query specified by the allQuery config option (defaults to 'query')
10856 triggerAction: 'query',
10858 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10859 * (defaults to 4, does not apply if editable = false)
10863 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10864 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10868 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10869 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10873 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10874 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10878 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10879 * when editable = true (defaults to false)
10881 selectOnFocus:false,
10883 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10885 queryParam: 'query',
10887 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10888 * when mode = 'remote' (defaults to 'Loading...')
10890 loadingText: 'Loading...',
10892 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10896 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10900 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10901 * traditional select (defaults to true)
10905 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10909 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10913 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10914 * listWidth has a higher value)
10918 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10919 * allow the user to set arbitrary text into the field (defaults to false)
10921 forceSelection:false,
10923 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10924 * if typeAhead = true (defaults to 250)
10926 typeAheadDelay : 250,
10928 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10929 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10931 valueNotFoundText : undefined,
10933 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10935 blockFocus : false,
10938 * @cfg {Boolean} disableClear Disable showing of clear button.
10940 disableClear : false,
10942 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10944 alwaysQuery : false,
10947 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10952 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10954 invalidClass : "has-warning",
10957 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10959 validClass : "has-success",
10962 * @cfg {Boolean} specialFilter (true|false) special filter default false
10964 specialFilter : false,
10976 btnPosition : 'right',
10977 triggerList : true,
10978 showToggleBtn : true,
10979 // element that contains real text value.. (when hidden is used..)
10981 getAutoCreate : function()
10988 if(!this.tickable){
10989 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10994 * ComboBox with tickable selections
10997 var align = this.labelAlign || this.parentLabelAlign();
11000 cls : 'form-group roo-combobox-tickable' //input-group
11005 cls : 'tickable-buttons',
11010 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11017 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11024 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11031 buttons.cn.unshift({
11033 cls: 'select2-search-field-input'
11039 Roo.each(buttons.cn, function(c){
11041 c.cls += ' btn-' + _this.size;
11044 if (_this.disabled) {
11055 cls: 'form-hidden-field'
11059 cls: 'select2-choices',
11063 cls: 'select2-search-field',
11075 cls: 'select2-container input-group select2-container-multi',
11080 // cls: 'typeahead typeahead-long dropdown-menu',
11081 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11086 if(this.hasFeedback && !this.allowBlank){
11090 cls: 'glyphicon form-control-feedback'
11093 combobox.cn.push(feedback);
11096 if (align ==='left' && this.fieldLabel.length) {
11098 Roo.log("left and has label");
11104 cls : 'control-label col-sm-' + this.labelWidth,
11105 html : this.fieldLabel
11109 cls : "col-sm-" + (12 - this.labelWidth),
11116 } else if ( this.fieldLabel.length) {
11122 //cls : 'input-group-addon',
11123 html : this.fieldLabel
11133 Roo.log(" no label && no align");
11140 ['xs','sm','md','lg'].map(function(size){
11141 if (settings[size]) {
11142 cfg.cls += ' col-' + size + '-' + settings[size];
11151 initEvents: function()
11155 throw "can not find store for combo";
11157 this.store = Roo.factory(this.store, Roo.data);
11160 this.initTickableEvents();
11164 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11166 if(this.hiddenName){
11168 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11170 this.hiddenField.dom.value =
11171 this.hiddenValue !== undefined ? this.hiddenValue :
11172 this.value !== undefined ? this.value : '';
11174 // prevent input submission
11175 this.el.dom.removeAttribute('name');
11176 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11181 // this.el.dom.setAttribute('autocomplete', 'off');
11184 var cls = 'x-combo-list';
11186 //this.list = new Roo.Layer({
11187 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11193 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11194 _this.list.setWidth(lw);
11197 this.list.on('mouseover', this.onViewOver, this);
11198 this.list.on('mousemove', this.onViewMove, this);
11200 this.list.on('scroll', this.onViewScroll, this);
11203 this.list.swallowEvent('mousewheel');
11204 this.assetHeight = 0;
11207 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11208 this.assetHeight += this.header.getHeight();
11211 this.innerList = this.list.createChild({cls:cls+'-inner'});
11212 this.innerList.on('mouseover', this.onViewOver, this);
11213 this.innerList.on('mousemove', this.onViewMove, this);
11214 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11216 if(this.allowBlank && !this.pageSize && !this.disableClear){
11217 this.footer = this.list.createChild({cls:cls+'-ft'});
11218 this.pageTb = new Roo.Toolbar(this.footer);
11222 this.footer = this.list.createChild({cls:cls+'-ft'});
11223 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11224 {pageSize: this.pageSize});
11228 if (this.pageTb && this.allowBlank && !this.disableClear) {
11230 this.pageTb.add(new Roo.Toolbar.Fill(), {
11231 cls: 'x-btn-icon x-btn-clear',
11233 handler: function()
11236 _this.clearValue();
11237 _this.onSelect(false, -1);
11242 this.assetHeight += this.footer.getHeight();
11247 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11250 this.view = new Roo.View(this.list, this.tpl, {
11251 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11253 //this.view.wrapEl.setDisplayed(false);
11254 this.view.on('click', this.onViewClick, this);
11258 this.store.on('beforeload', this.onBeforeLoad, this);
11259 this.store.on('load', this.onLoad, this);
11260 this.store.on('loadexception', this.onLoadException, this);
11262 if(this.resizable){
11263 this.resizer = new Roo.Resizable(this.list, {
11264 pinned:true, handles:'se'
11266 this.resizer.on('resize', function(r, w, h){
11267 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11268 this.listWidth = w;
11269 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11270 this.restrictHeight();
11272 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11275 if(!this.editable){
11276 this.editable = true;
11277 this.setEditable(false);
11282 if (typeof(this.events.add.listeners) != 'undefined') {
11284 this.addicon = this.wrap.createChild(
11285 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11287 this.addicon.on('click', function(e) {
11288 this.fireEvent('add', this);
11291 if (typeof(this.events.edit.listeners) != 'undefined') {
11293 this.editicon = this.wrap.createChild(
11294 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11295 if (this.addicon) {
11296 this.editicon.setStyle('margin-left', '40px');
11298 this.editicon.on('click', function(e) {
11300 // we fire even if inothing is selected..
11301 this.fireEvent('edit', this, this.lastData );
11307 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11308 "up" : function(e){
11309 this.inKeyMode = true;
11313 "down" : function(e){
11314 if(!this.isExpanded()){
11315 this.onTriggerClick();
11317 this.inKeyMode = true;
11322 "enter" : function(e){
11323 // this.onViewClick();
11327 if(this.fireEvent("specialkey", this, e)){
11328 this.onViewClick(false);
11334 "esc" : function(e){
11338 "tab" : function(e){
11341 if(this.fireEvent("specialkey", this, e)){
11342 this.onViewClick(false);
11350 doRelay : function(foo, bar, hname){
11351 if(hname == 'down' || this.scope.isExpanded()){
11352 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11361 this.queryDelay = Math.max(this.queryDelay || 10,
11362 this.mode == 'local' ? 10 : 250);
11365 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11367 if(this.typeAhead){
11368 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11370 if(this.editable !== false){
11371 this.inputEl().on("keyup", this.onKeyUp, this);
11373 if(this.forceSelection){
11374 this.inputEl().on('blur', this.doForce, this);
11378 this.choices = this.el.select('ul.select2-choices', true).first();
11379 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11383 initTickableEvents: function()
11387 if(this.hiddenName){
11389 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11391 this.hiddenField.dom.value =
11392 this.hiddenValue !== undefined ? this.hiddenValue :
11393 this.value !== undefined ? this.value : '';
11395 // prevent input submission
11396 this.el.dom.removeAttribute('name');
11397 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11402 // this.list = this.el.select('ul.dropdown-menu',true).first();
11404 this.choices = this.el.select('ul.select2-choices', true).first();
11405 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11406 if(this.triggerList){
11407 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11410 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11411 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11413 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11414 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11416 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11417 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11419 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11420 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11421 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11424 this.cancelBtn.hide();
11429 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11430 _this.list.setWidth(lw);
11433 this.list.on('mouseover', this.onViewOver, this);
11434 this.list.on('mousemove', this.onViewMove, this);
11436 this.list.on('scroll', this.onViewScroll, this);
11439 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>';
11442 this.view = new Roo.View(this.list, this.tpl, {
11443 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11446 //this.view.wrapEl.setDisplayed(false);
11447 this.view.on('click', this.onViewClick, this);
11451 this.store.on('beforeload', this.onBeforeLoad, this);
11452 this.store.on('load', this.onLoad, this);
11453 this.store.on('loadexception', this.onLoadException, this);
11456 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11457 "up" : function(e){
11458 this.inKeyMode = true;
11462 "down" : function(e){
11463 this.inKeyMode = true;
11467 "enter" : function(e){
11468 if(this.fireEvent("specialkey", this, e)){
11469 this.onViewClick(false);
11475 "esc" : function(e){
11476 this.onTickableFooterButtonClick(e, false, false);
11479 "tab" : function(e){
11480 this.fireEvent("specialkey", this, e);
11482 this.onTickableFooterButtonClick(e, false, false);
11489 doRelay : function(e, fn, key){
11490 if(this.scope.isExpanded()){
11491 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11500 this.queryDelay = Math.max(this.queryDelay || 10,
11501 this.mode == 'local' ? 10 : 250);
11504 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11506 if(this.typeAhead){
11507 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11510 if(this.editable !== false){
11511 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11516 onDestroy : function(){
11518 this.view.setStore(null);
11519 this.view.el.removeAllListeners();
11520 this.view.el.remove();
11521 this.view.purgeListeners();
11524 this.list.dom.innerHTML = '';
11528 this.store.un('beforeload', this.onBeforeLoad, this);
11529 this.store.un('load', this.onLoad, this);
11530 this.store.un('loadexception', this.onLoadException, this);
11532 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11536 fireKey : function(e){
11537 if(e.isNavKeyPress() && !this.list.isVisible()){
11538 this.fireEvent("specialkey", this, e);
11543 onResize: function(w, h){
11544 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11546 // if(typeof w != 'number'){
11547 // // we do not handle it!?!?
11550 // var tw = this.trigger.getWidth();
11551 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11552 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11554 // this.inputEl().setWidth( this.adjustWidth('input', x));
11556 // //this.trigger.setStyle('left', x+'px');
11558 // if(this.list && this.listWidth === undefined){
11559 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11560 // this.list.setWidth(lw);
11561 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11569 * Allow or prevent the user from directly editing the field text. If false is passed,
11570 * the user will only be able to select from the items defined in the dropdown list. This method
11571 * is the runtime equivalent of setting the 'editable' config option at config time.
11572 * @param {Boolean} value True to allow the user to directly edit the field text
11574 setEditable : function(value){
11575 if(value == this.editable){
11578 this.editable = value;
11580 this.inputEl().dom.setAttribute('readOnly', true);
11581 this.inputEl().on('mousedown', this.onTriggerClick, this);
11582 this.inputEl().addClass('x-combo-noedit');
11584 this.inputEl().dom.setAttribute('readOnly', false);
11585 this.inputEl().un('mousedown', this.onTriggerClick, this);
11586 this.inputEl().removeClass('x-combo-noedit');
11592 onBeforeLoad : function(combo,opts){
11593 if(!this.hasFocus){
11597 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11599 this.restrictHeight();
11600 this.selectedIndex = -1;
11604 onLoad : function(){
11606 this.hasQuery = false;
11608 if(!this.hasFocus){
11612 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11613 this.loading.hide();
11616 if(this.store.getCount() > 0){
11618 this.restrictHeight();
11619 if(this.lastQuery == this.allQuery){
11620 if(this.editable && !this.tickable){
11621 this.inputEl().dom.select();
11625 !this.selectByValue(this.value, true) &&
11628 !this.store.lastOptions ||
11629 typeof(this.store.lastOptions.add) == 'undefined' ||
11630 this.store.lastOptions.add != true
11633 this.select(0, true);
11636 if(this.autoFocus){
11639 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11640 this.taTask.delay(this.typeAheadDelay);
11644 this.onEmptyResults();
11650 onLoadException : function()
11652 this.hasQuery = false;
11654 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11655 this.loading.hide();
11658 if(this.tickable && this.editable){
11664 Roo.log(this.store.reader.jsonData);
11665 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11667 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11673 onTypeAhead : function(){
11674 if(this.store.getCount() > 0){
11675 var r = this.store.getAt(0);
11676 var newValue = r.data[this.displayField];
11677 var len = newValue.length;
11678 var selStart = this.getRawValue().length;
11680 if(selStart != len){
11681 this.setRawValue(newValue);
11682 this.selectText(selStart, newValue.length);
11688 onSelect : function(record, index){
11690 if(this.fireEvent('beforeselect', this, record, index) !== false){
11692 this.setFromData(index > -1 ? record.data : false);
11695 this.fireEvent('select', this, record, index);
11700 * Returns the currently selected field value or empty string if no value is set.
11701 * @return {String} value The selected value
11703 getValue : function(){
11706 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11709 if(this.valueField){
11710 return typeof this.value != 'undefined' ? this.value : '';
11712 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11717 * Clears any text/value currently set in the field
11719 clearValue : function(){
11720 if(this.hiddenField){
11721 this.hiddenField.dom.value = '';
11724 this.setRawValue('');
11725 this.lastSelectionText = '';
11726 this.lastData = false;
11731 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11732 * will be displayed in the field. If the value does not match the data value of an existing item,
11733 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11734 * Otherwise the field will be blank (although the value will still be set).
11735 * @param {String} value The value to match
11737 setValue : function(v){
11744 if(this.valueField){
11745 var r = this.findRecord(this.valueField, v);
11747 text = r.data[this.displayField];
11748 }else if(this.valueNotFoundText !== undefined){
11749 text = this.valueNotFoundText;
11752 this.lastSelectionText = text;
11753 if(this.hiddenField){
11754 this.hiddenField.dom.value = v;
11756 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11760 * @property {Object} the last set data for the element
11765 * Sets the value of the field based on a object which is related to the record format for the store.
11766 * @param {Object} value the value to set as. or false on reset?
11768 setFromData : function(o){
11775 var dv = ''; // display value
11776 var vv = ''; // value value..
11778 if (this.displayField) {
11779 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11781 // this is an error condition!!!
11782 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11785 if(this.valueField){
11786 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11789 if(this.hiddenField){
11790 this.hiddenField.dom.value = vv;
11792 this.lastSelectionText = dv;
11793 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11797 // no hidden field.. - we store the value in 'value', but still display
11798 // display field!!!!
11799 this.lastSelectionText = dv;
11800 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11806 reset : function(){
11807 // overridden so that last data is reset..
11814 this.setValue(this.originalValue);
11815 this.clearInvalid();
11816 this.lastData = false;
11818 this.view.clearSelections();
11822 findRecord : function(prop, value){
11824 if(this.store.getCount() > 0){
11825 this.store.each(function(r){
11826 if(r.data[prop] == value){
11836 getName: function()
11838 // returns hidden if it's set..
11839 if (!this.rendered) {return ''};
11840 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11844 onViewMove : function(e, t){
11845 this.inKeyMode = false;
11849 onViewOver : function(e, t){
11850 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11853 var item = this.view.findItemFromChild(t);
11856 var index = this.view.indexOf(item);
11857 this.select(index, false);
11862 onViewClick : function(view, doFocus, el, e)
11864 var index = this.view.getSelectedIndexes()[0];
11866 var r = this.store.getAt(index);
11870 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11877 Roo.each(this.tickItems, function(v,k){
11879 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11880 _this.tickItems.splice(k, 1);
11882 if(typeof(e) == 'undefined' && view == false){
11883 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11895 this.tickItems.push(r.data);
11897 if(typeof(e) == 'undefined' && view == false){
11898 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11905 this.onSelect(r, index);
11907 if(doFocus !== false && !this.blockFocus){
11908 this.inputEl().focus();
11913 restrictHeight : function(){
11914 //this.innerList.dom.style.height = '';
11915 //var inner = this.innerList.dom;
11916 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11917 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11918 //this.list.beginUpdate();
11919 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11920 this.list.alignTo(this.inputEl(), this.listAlign);
11921 this.list.alignTo(this.inputEl(), this.listAlign);
11922 //this.list.endUpdate();
11926 onEmptyResults : function(){
11928 if(this.tickable && this.editable){
11929 this.restrictHeight();
11937 * Returns true if the dropdown list is expanded, else false.
11939 isExpanded : function(){
11940 return this.list.isVisible();
11944 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11945 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11946 * @param {String} value The data value of the item to select
11947 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11948 * selected item if it is not currently in view (defaults to true)
11949 * @return {Boolean} True if the value matched an item in the list, else false
11951 selectByValue : function(v, scrollIntoView){
11952 if(v !== undefined && v !== null){
11953 var r = this.findRecord(this.valueField || this.displayField, v);
11955 this.select(this.store.indexOf(r), scrollIntoView);
11963 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11964 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11965 * @param {Number} index The zero-based index of the list item to select
11966 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11967 * selected item if it is not currently in view (defaults to true)
11969 select : function(index, scrollIntoView){
11970 this.selectedIndex = index;
11971 this.view.select(index);
11972 if(scrollIntoView !== false){
11973 var el = this.view.getNode(index);
11975 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11978 this.list.scrollChildIntoView(el, false);
11984 selectNext : function(){
11985 var ct = this.store.getCount();
11987 if(this.selectedIndex == -1){
11989 }else if(this.selectedIndex < ct-1){
11990 this.select(this.selectedIndex+1);
11996 selectPrev : function(){
11997 var ct = this.store.getCount();
11999 if(this.selectedIndex == -1){
12001 }else if(this.selectedIndex != 0){
12002 this.select(this.selectedIndex-1);
12008 onKeyUp : function(e){
12009 if(this.editable !== false && !e.isSpecialKey()){
12010 this.lastKey = e.getKey();
12011 this.dqTask.delay(this.queryDelay);
12016 validateBlur : function(){
12017 return !this.list || !this.list.isVisible();
12021 initQuery : function(){
12023 var v = this.getRawValue();
12025 if(this.tickable && this.editable){
12026 v = this.tickableInputEl().getValue();
12033 doForce : function(){
12034 if(this.inputEl().dom.value.length > 0){
12035 this.inputEl().dom.value =
12036 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12042 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12043 * query allowing the query action to be canceled if needed.
12044 * @param {String} query The SQL query to execute
12045 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12046 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12047 * saved in the current store (defaults to false)
12049 doQuery : function(q, forceAll){
12051 if(q === undefined || q === null){
12056 forceAll: forceAll,
12060 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12065 forceAll = qe.forceAll;
12066 if(forceAll === true || (q.length >= this.minChars)){
12068 this.hasQuery = true;
12070 if(this.lastQuery != q || this.alwaysQuery){
12071 this.lastQuery = q;
12072 if(this.mode == 'local'){
12073 this.selectedIndex = -1;
12075 this.store.clearFilter();
12078 if(this.specialFilter){
12079 this.fireEvent('specialfilter', this);
12084 this.store.filter(this.displayField, q);
12089 this.store.baseParams[this.queryParam] = q;
12091 var options = {params : this.getParams(q)};
12094 options.add = true;
12095 options.params.start = this.page * this.pageSize;
12098 this.store.load(options);
12101 * this code will make the page width larger, at the beginning, the list not align correctly,
12102 * we should expand the list on onLoad
12103 * so command out it
12108 this.selectedIndex = -1;
12113 this.loadNext = false;
12117 getParams : function(q){
12119 //p[this.queryParam] = q;
12123 p.limit = this.pageSize;
12129 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12131 collapse : function(){
12132 if(!this.isExpanded()){
12139 this.hasFocus = false;
12141 this.cancelBtn.hide();
12142 this.trigger.show();
12145 this.tickableInputEl().dom.value = '';
12146 this.tickableInputEl().blur();
12151 Roo.get(document).un('mousedown', this.collapseIf, this);
12152 Roo.get(document).un('mousewheel', this.collapseIf, this);
12153 if (!this.editable) {
12154 Roo.get(document).un('keydown', this.listKeyPress, this);
12156 this.fireEvent('collapse', this);
12160 collapseIf : function(e){
12161 var in_combo = e.within(this.el);
12162 var in_list = e.within(this.list);
12163 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12165 if (in_combo || in_list || is_list) {
12166 //e.stopPropagation();
12171 this.onTickableFooterButtonClick(e, false, false);
12179 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12181 expand : function(){
12183 if(this.isExpanded() || !this.hasFocus){
12187 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12188 this.list.setWidth(lw);
12195 this.restrictHeight();
12199 this.tickItems = Roo.apply([], this.item);
12202 this.cancelBtn.show();
12203 this.trigger.hide();
12206 this.tickableInputEl().focus();
12211 Roo.get(document).on('mousedown', this.collapseIf, this);
12212 Roo.get(document).on('mousewheel', this.collapseIf, this);
12213 if (!this.editable) {
12214 Roo.get(document).on('keydown', this.listKeyPress, this);
12217 this.fireEvent('expand', this);
12221 // Implements the default empty TriggerField.onTriggerClick function
12222 onTriggerClick : function(e)
12224 Roo.log('trigger click');
12226 if(this.disabled || !this.triggerList){
12231 this.loadNext = false;
12233 if(this.isExpanded()){
12235 if (!this.blockFocus) {
12236 this.inputEl().focus();
12240 this.hasFocus = true;
12241 if(this.triggerAction == 'all') {
12242 this.doQuery(this.allQuery, true);
12244 this.doQuery(this.getRawValue());
12246 if (!this.blockFocus) {
12247 this.inputEl().focus();
12252 onTickableTriggerClick : function(e)
12259 this.loadNext = false;
12260 this.hasFocus = true;
12262 if(this.triggerAction == 'all') {
12263 this.doQuery(this.allQuery, true);
12265 this.doQuery(this.getRawValue());
12269 onSearchFieldClick : function(e)
12271 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12272 this.onTickableFooterButtonClick(e, false, false);
12276 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12281 this.loadNext = false;
12282 this.hasFocus = true;
12284 if(this.triggerAction == 'all') {
12285 this.doQuery(this.allQuery, true);
12287 this.doQuery(this.getRawValue());
12291 listKeyPress : function(e)
12293 //Roo.log('listkeypress');
12294 // scroll to first matching element based on key pres..
12295 if (e.isSpecialKey()) {
12298 var k = String.fromCharCode(e.getKey()).toUpperCase();
12301 var csel = this.view.getSelectedNodes();
12302 var cselitem = false;
12304 var ix = this.view.indexOf(csel[0]);
12305 cselitem = this.store.getAt(ix);
12306 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12312 this.store.each(function(v) {
12314 // start at existing selection.
12315 if (cselitem.id == v.id) {
12321 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12322 match = this.store.indexOf(v);
12328 if (match === false) {
12329 return true; // no more action?
12332 this.view.select(match);
12333 var sn = Roo.get(this.view.getSelectedNodes()[0])
12334 sn.scrollIntoView(sn.dom.parentNode, false);
12337 onViewScroll : function(e, t){
12339 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){
12343 this.hasQuery = true;
12345 this.loading = this.list.select('.loading', true).first();
12347 if(this.loading === null){
12348 this.list.createChild({
12350 cls: 'loading select2-more-results select2-active',
12351 html: 'Loading more results...'
12354 this.loading = this.list.select('.loading', true).first();
12356 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12358 this.loading.hide();
12361 this.loading.show();
12366 this.loadNext = true;
12368 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12373 addItem : function(o)
12375 var dv = ''; // display value
12377 if (this.displayField) {
12378 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12380 // this is an error condition!!!
12381 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12388 var choice = this.choices.createChild({
12390 cls: 'select2-search-choice',
12399 cls: 'select2-search-choice-close',
12404 }, this.searchField);
12406 var close = choice.select('a.select2-search-choice-close', true).first()
12408 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12416 this.inputEl().dom.value = '';
12421 onRemoveItem : function(e, _self, o)
12423 e.preventDefault();
12425 this.lastItem = Roo.apply([], this.item);
12427 var index = this.item.indexOf(o.data) * 1;
12430 Roo.log('not this item?!');
12434 this.item.splice(index, 1);
12439 this.fireEvent('remove', this, e);
12445 syncValue : function()
12447 if(!this.item.length){
12454 Roo.each(this.item, function(i){
12455 if(_this.valueField){
12456 value.push(i[_this.valueField]);
12463 this.value = value.join(',');
12465 if(this.hiddenField){
12466 this.hiddenField.dom.value = this.value;
12470 clearItem : function()
12472 if(!this.multiple){
12478 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12487 inputEl: function ()
12490 return this.searchField;
12492 return this.el.select('input.form-control',true).first();
12496 onTickableFooterButtonClick : function(e, btn, el)
12498 e.preventDefault();
12500 this.lastItem = Roo.apply([], this.item);
12502 if(btn && btn.name == 'cancel'){
12503 this.tickItems = Roo.apply([], this.item);
12512 Roo.each(this.tickItems, function(o){
12520 validate : function()
12522 var v = this.getRawValue();
12525 v = this.getValue();
12528 if(this.disabled || this.allowBlank || v.length){
12533 this.markInvalid();
12537 tickableInputEl : function()
12539 if(!this.tickable || !this.editable){
12540 return this.inputEl();
12543 return this.inputEl().select('.select2-search-field-input', true).first();
12549 * @cfg {Boolean} grow
12553 * @cfg {Number} growMin
12557 * @cfg {Number} growMax
12567 * Ext JS Library 1.1.1
12568 * Copyright(c) 2006-2007, Ext JS, LLC.
12570 * Originally Released Under LGPL - original licence link has changed is not relivant.
12573 * <script type="text/javascript">
12578 * @extends Roo.util.Observable
12579 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12580 * This class also supports single and multi selection modes. <br>
12581 * Create a data model bound view:
12583 var store = new Roo.data.Store(...);
12585 var view = new Roo.View({
12587 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12589 singleSelect: true,
12590 selectedClass: "ydataview-selected",
12594 // listen for node click?
12595 view.on("click", function(vw, index, node, e){
12596 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12600 dataModel.load("foobar.xml");
12602 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12604 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12605 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12607 * Note: old style constructor is still suported (container, template, config)
12610 * Create a new View
12611 * @param {Object} config The config object
12614 Roo.View = function(config, depreciated_tpl, depreciated_config){
12616 this.parent = false;
12618 if (typeof(depreciated_tpl) == 'undefined') {
12619 // new way.. - universal constructor.
12620 Roo.apply(this, config);
12621 this.el = Roo.get(this.el);
12624 this.el = Roo.get(config);
12625 this.tpl = depreciated_tpl;
12626 Roo.apply(this, depreciated_config);
12628 this.wrapEl = this.el.wrap().wrap();
12629 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12632 if(typeof(this.tpl) == "string"){
12633 this.tpl = new Roo.Template(this.tpl);
12635 // support xtype ctors..
12636 this.tpl = new Roo.factory(this.tpl, Roo);
12640 this.tpl.compile();
12645 * @event beforeclick
12646 * Fires before a click is processed. Returns false to cancel the default action.
12647 * @param {Roo.View} this
12648 * @param {Number} index The index of the target node
12649 * @param {HTMLElement} node The target node
12650 * @param {Roo.EventObject} e The raw event object
12652 "beforeclick" : true,
12655 * Fires when a template node is clicked.
12656 * @param {Roo.View} this
12657 * @param {Number} index The index of the target node
12658 * @param {HTMLElement} node The target node
12659 * @param {Roo.EventObject} e The raw event object
12664 * Fires when a template node is double clicked.
12665 * @param {Roo.View} this
12666 * @param {Number} index The index of the target node
12667 * @param {HTMLElement} node The target node
12668 * @param {Roo.EventObject} e The raw event object
12672 * @event contextmenu
12673 * Fires when a template node is right clicked.
12674 * @param {Roo.View} this
12675 * @param {Number} index The index of the target node
12676 * @param {HTMLElement} node The target node
12677 * @param {Roo.EventObject} e The raw event object
12679 "contextmenu" : true,
12681 * @event selectionchange
12682 * Fires when the selected nodes change.
12683 * @param {Roo.View} this
12684 * @param {Array} selections Array of the selected nodes
12686 "selectionchange" : true,
12689 * @event beforeselect
12690 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12691 * @param {Roo.View} this
12692 * @param {HTMLElement} node The node to be selected
12693 * @param {Array} selections Array of currently selected nodes
12695 "beforeselect" : true,
12697 * @event preparedata
12698 * Fires on every row to render, to allow you to change the data.
12699 * @param {Roo.View} this
12700 * @param {Object} data to be rendered (change this)
12702 "preparedata" : true
12710 "click": this.onClick,
12711 "dblclick": this.onDblClick,
12712 "contextmenu": this.onContextMenu,
12716 this.selections = [];
12718 this.cmp = new Roo.CompositeElementLite([]);
12720 this.store = Roo.factory(this.store, Roo.data);
12721 this.setStore(this.store, true);
12724 if ( this.footer && this.footer.xtype) {
12726 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12728 this.footer.dataSource = this.store
12729 this.footer.container = fctr;
12730 this.footer = Roo.factory(this.footer, Roo);
12731 fctr.insertFirst(this.el);
12733 // this is a bit insane - as the paging toolbar seems to detach the el..
12734 // dom.parentNode.parentNode.parentNode
12735 // they get detached?
12739 Roo.View.superclass.constructor.call(this);
12744 Roo.extend(Roo.View, Roo.util.Observable, {
12747 * @cfg {Roo.data.Store} store Data store to load data from.
12752 * @cfg {String|Roo.Element} el The container element.
12757 * @cfg {String|Roo.Template} tpl The template used by this View
12761 * @cfg {String} dataName the named area of the template to use as the data area
12762 * Works with domtemplates roo-name="name"
12766 * @cfg {String} selectedClass The css class to add to selected nodes
12768 selectedClass : "x-view-selected",
12770 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12775 * @cfg {String} text to display on mask (default Loading)
12779 * @cfg {Boolean} multiSelect Allow multiple selection
12781 multiSelect : false,
12783 * @cfg {Boolean} singleSelect Allow single selection
12785 singleSelect: false,
12788 * @cfg {Boolean} toggleSelect - selecting
12790 toggleSelect : false,
12793 * @cfg {Boolean} tickable - selecting
12798 * Returns the element this view is bound to.
12799 * @return {Roo.Element}
12801 getEl : function(){
12802 return this.wrapEl;
12808 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12810 refresh : function(){
12811 //Roo.log('refresh');
12814 // if we are using something like 'domtemplate', then
12815 // the what gets used is:
12816 // t.applySubtemplate(NAME, data, wrapping data..)
12817 // the outer template then get' applied with
12818 // the store 'extra data'
12819 // and the body get's added to the
12820 // roo-name="data" node?
12821 // <span class='roo-tpl-{name}'></span> ?????
12825 this.clearSelections();
12826 this.el.update("");
12828 var records = this.store.getRange();
12829 if(records.length < 1) {
12831 // is this valid?? = should it render a template??
12833 this.el.update(this.emptyText);
12837 if (this.dataName) {
12838 this.el.update(t.apply(this.store.meta)); //????
12839 el = this.el.child('.roo-tpl-' + this.dataName);
12842 for(var i = 0, len = records.length; i < len; i++){
12843 var data = this.prepareData(records[i].data, i, records[i]);
12844 this.fireEvent("preparedata", this, data, i, records[i]);
12846 var d = Roo.apply({}, data);
12849 Roo.apply(d, {'roo-id' : Roo.id()});
12853 Roo.each(this.parent.item, function(item){
12854 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12857 Roo.apply(d, {'roo-data-checked' : 'checked'});
12861 html[html.length] = Roo.util.Format.trim(
12863 t.applySubtemplate(this.dataName, d, this.store.meta) :
12870 el.update(html.join(""));
12871 this.nodes = el.dom.childNodes;
12872 this.updateIndexes(0);
12877 * Function to override to reformat the data that is sent to
12878 * the template for each node.
12879 * DEPRICATED - use the preparedata event handler.
12880 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12881 * a JSON object for an UpdateManager bound view).
12883 prepareData : function(data, index, record)
12885 this.fireEvent("preparedata", this, data, index, record);
12889 onUpdate : function(ds, record){
12890 // Roo.log('on update');
12891 this.clearSelections();
12892 var index = this.store.indexOf(record);
12893 var n = this.nodes[index];
12894 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12895 n.parentNode.removeChild(n);
12896 this.updateIndexes(index, index);
12902 onAdd : function(ds, records, index)
12904 //Roo.log(['on Add', ds, records, index] );
12905 this.clearSelections();
12906 if(this.nodes.length == 0){
12910 var n = this.nodes[index];
12911 for(var i = 0, len = records.length; i < len; i++){
12912 var d = this.prepareData(records[i].data, i, records[i]);
12914 this.tpl.insertBefore(n, d);
12917 this.tpl.append(this.el, d);
12920 this.updateIndexes(index);
12923 onRemove : function(ds, record, index){
12924 // Roo.log('onRemove');
12925 this.clearSelections();
12926 var el = this.dataName ?
12927 this.el.child('.roo-tpl-' + this.dataName) :
12930 el.dom.removeChild(this.nodes[index]);
12931 this.updateIndexes(index);
12935 * Refresh an individual node.
12936 * @param {Number} index
12938 refreshNode : function(index){
12939 this.onUpdate(this.store, this.store.getAt(index));
12942 updateIndexes : function(startIndex, endIndex){
12943 var ns = this.nodes;
12944 startIndex = startIndex || 0;
12945 endIndex = endIndex || ns.length - 1;
12946 for(var i = startIndex; i <= endIndex; i++){
12947 ns[i].nodeIndex = i;
12952 * Changes the data store this view uses and refresh the view.
12953 * @param {Store} store
12955 setStore : function(store, initial){
12956 if(!initial && this.store){
12957 this.store.un("datachanged", this.refresh);
12958 this.store.un("add", this.onAdd);
12959 this.store.un("remove", this.onRemove);
12960 this.store.un("update", this.onUpdate);
12961 this.store.un("clear", this.refresh);
12962 this.store.un("beforeload", this.onBeforeLoad);
12963 this.store.un("load", this.onLoad);
12964 this.store.un("loadexception", this.onLoad);
12968 store.on("datachanged", this.refresh, this);
12969 store.on("add", this.onAdd, this);
12970 store.on("remove", this.onRemove, this);
12971 store.on("update", this.onUpdate, this);
12972 store.on("clear", this.refresh, this);
12973 store.on("beforeload", this.onBeforeLoad, this);
12974 store.on("load", this.onLoad, this);
12975 store.on("loadexception", this.onLoad, this);
12983 * onbeforeLoad - masks the loading area.
12986 onBeforeLoad : function(store,opts)
12988 //Roo.log('onBeforeLoad');
12990 this.el.update("");
12992 this.el.mask(this.mask ? this.mask : "Loading" );
12994 onLoad : function ()
13001 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13002 * @param {HTMLElement} node
13003 * @return {HTMLElement} The template node
13005 findItemFromChild : function(node){
13006 var el = this.dataName ?
13007 this.el.child('.roo-tpl-' + this.dataName,true) :
13010 if(!node || node.parentNode == el){
13013 var p = node.parentNode;
13014 while(p && p != el){
13015 if(p.parentNode == el){
13024 onClick : function(e){
13025 var item = this.findItemFromChild(e.getTarget());
13027 var index = this.indexOf(item);
13028 if(this.onItemClick(item, index, e) !== false){
13029 this.fireEvent("click", this, index, item, e);
13032 this.clearSelections();
13037 onContextMenu : function(e){
13038 var item = this.findItemFromChild(e.getTarget());
13040 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13045 onDblClick : function(e){
13046 var item = this.findItemFromChild(e.getTarget());
13048 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13052 onItemClick : function(item, index, e)
13054 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13057 if (this.toggleSelect) {
13058 var m = this.isSelected(item) ? 'unselect' : 'select';
13061 _t[m](item, true, false);
13064 if(this.multiSelect || this.singleSelect){
13065 if(this.multiSelect && e.shiftKey && this.lastSelection){
13066 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13068 this.select(item, this.multiSelect && e.ctrlKey);
13069 this.lastSelection = item;
13072 if(!this.tickable){
13073 e.preventDefault();
13081 * Get the number of selected nodes.
13084 getSelectionCount : function(){
13085 return this.selections.length;
13089 * Get the currently selected nodes.
13090 * @return {Array} An array of HTMLElements
13092 getSelectedNodes : function(){
13093 return this.selections;
13097 * Get the indexes of the selected nodes.
13100 getSelectedIndexes : function(){
13101 var indexes = [], s = this.selections;
13102 for(var i = 0, len = s.length; i < len; i++){
13103 indexes.push(s[i].nodeIndex);
13109 * Clear all selections
13110 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13112 clearSelections : function(suppressEvent){
13113 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13114 this.cmp.elements = this.selections;
13115 this.cmp.removeClass(this.selectedClass);
13116 this.selections = [];
13117 if(!suppressEvent){
13118 this.fireEvent("selectionchange", this, this.selections);
13124 * Returns true if the passed node is selected
13125 * @param {HTMLElement/Number} node The node or node index
13126 * @return {Boolean}
13128 isSelected : function(node){
13129 var s = this.selections;
13133 node = this.getNode(node);
13134 return s.indexOf(node) !== -1;
13139 * @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
13140 * @param {Boolean} keepExisting (optional) true to keep existing selections
13141 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13143 select : function(nodeInfo, keepExisting, suppressEvent){
13144 if(nodeInfo instanceof Array){
13146 this.clearSelections(true);
13148 for(var i = 0, len = nodeInfo.length; i < len; i++){
13149 this.select(nodeInfo[i], true, true);
13153 var node = this.getNode(nodeInfo);
13154 if(!node || this.isSelected(node)){
13155 return; // already selected.
13158 this.clearSelections(true);
13161 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13162 Roo.fly(node).addClass(this.selectedClass);
13163 this.selections.push(node);
13164 if(!suppressEvent){
13165 this.fireEvent("selectionchange", this, this.selections);
13173 * @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
13174 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13175 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13177 unselect : function(nodeInfo, keepExisting, suppressEvent)
13179 if(nodeInfo instanceof Array){
13180 Roo.each(this.selections, function(s) {
13181 this.unselect(s, nodeInfo);
13185 var node = this.getNode(nodeInfo);
13186 if(!node || !this.isSelected(node)){
13187 //Roo.log("not selected");
13188 return; // not selected.
13192 Roo.each(this.selections, function(s) {
13194 Roo.fly(node).removeClass(this.selectedClass);
13201 this.selections= ns;
13202 this.fireEvent("selectionchange", this, this.selections);
13206 * Gets a template node.
13207 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13208 * @return {HTMLElement} The node or null if it wasn't found
13210 getNode : function(nodeInfo){
13211 if(typeof nodeInfo == "string"){
13212 return document.getElementById(nodeInfo);
13213 }else if(typeof nodeInfo == "number"){
13214 return this.nodes[nodeInfo];
13220 * Gets a range template nodes.
13221 * @param {Number} startIndex
13222 * @param {Number} endIndex
13223 * @return {Array} An array of nodes
13225 getNodes : function(start, end){
13226 var ns = this.nodes;
13227 start = start || 0;
13228 end = typeof end == "undefined" ? ns.length - 1 : end;
13231 for(var i = start; i <= end; i++){
13235 for(var i = start; i >= end; i--){
13243 * Finds the index of the passed node
13244 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13245 * @return {Number} The index of the node or -1
13247 indexOf : function(node){
13248 node = this.getNode(node);
13249 if(typeof node.nodeIndex == "number"){
13250 return node.nodeIndex;
13252 var ns = this.nodes;
13253 for(var i = 0, len = ns.length; i < len; i++){
13264 * based on jquery fullcalendar
13268 Roo.bootstrap = Roo.bootstrap || {};
13270 * @class Roo.bootstrap.Calendar
13271 * @extends Roo.bootstrap.Component
13272 * Bootstrap Calendar class
13273 * @cfg {Boolean} loadMask (true|false) default false
13274 * @cfg {Object} header generate the user specific header of the calendar, default false
13277 * Create a new Container
13278 * @param {Object} config The config object
13283 Roo.bootstrap.Calendar = function(config){
13284 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13288 * Fires when a date is selected
13289 * @param {DatePicker} this
13290 * @param {Date} date The selected date
13294 * @event monthchange
13295 * Fires when the displayed month changes
13296 * @param {DatePicker} this
13297 * @param {Date} date The selected month
13299 'monthchange': true,
13301 * @event evententer
13302 * Fires when mouse over an event
13303 * @param {Calendar} this
13304 * @param {event} Event
13306 'evententer': true,
13308 * @event eventleave
13309 * Fires when the mouse leaves an
13310 * @param {Calendar} this
13313 'eventleave': true,
13315 * @event eventclick
13316 * Fires when the mouse click an
13317 * @param {Calendar} this
13326 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13329 * @cfg {Number} startDay
13330 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13338 getAutoCreate : function(){
13341 var fc_button = function(name, corner, style, content ) {
13342 return Roo.apply({},{
13344 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13346 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13349 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13360 style : 'width:100%',
13367 cls : 'fc-header-left',
13369 fc_button('prev', 'left', 'arrow', '‹' ),
13370 fc_button('next', 'right', 'arrow', '›' ),
13371 { tag: 'span', cls: 'fc-header-space' },
13372 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13380 cls : 'fc-header-center',
13384 cls: 'fc-header-title',
13387 html : 'month / year'
13395 cls : 'fc-header-right',
13397 /* fc_button('month', 'left', '', 'month' ),
13398 fc_button('week', '', '', 'week' ),
13399 fc_button('day', 'right', '', 'day' )
13411 header = this.header;
13414 var cal_heads = function() {
13416 // fixme - handle this.
13418 for (var i =0; i < Date.dayNames.length; i++) {
13419 var d = Date.dayNames[i];
13422 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13423 html : d.substring(0,3)
13427 ret[0].cls += ' fc-first';
13428 ret[6].cls += ' fc-last';
13431 var cal_cell = function(n) {
13434 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13439 cls: 'fc-day-number',
13443 cls: 'fc-day-content',
13447 style: 'position: relative;' // height: 17px;
13459 var cal_rows = function() {
13462 for (var r = 0; r < 6; r++) {
13469 for (var i =0; i < Date.dayNames.length; i++) {
13470 var d = Date.dayNames[i];
13471 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13474 row.cn[0].cls+=' fc-first';
13475 row.cn[0].cn[0].style = 'min-height:90px';
13476 row.cn[6].cls+=' fc-last';
13480 ret[0].cls += ' fc-first';
13481 ret[4].cls += ' fc-prev-last';
13482 ret[5].cls += ' fc-last';
13489 cls: 'fc-border-separate',
13490 style : 'width:100%',
13498 cls : 'fc-first fc-last',
13516 cls : 'fc-content',
13517 style : "position: relative;",
13520 cls : 'fc-view fc-view-month fc-grid',
13521 style : 'position: relative',
13522 unselectable : 'on',
13525 cls : 'fc-event-container',
13526 style : 'position:absolute;z-index:8;top:0;left:0;'
13544 initEvents : function()
13547 throw "can not find store for calendar";
13553 style: "text-align:center",
13557 style: "background-color:white;width:50%;margin:250 auto",
13561 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13572 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13574 var size = this.el.select('.fc-content', true).first().getSize();
13575 this.maskEl.setSize(size.width, size.height);
13576 this.maskEl.enableDisplayMode("block");
13577 if(!this.loadMask){
13578 this.maskEl.hide();
13581 this.store = Roo.factory(this.store, Roo.data);
13582 this.store.on('load', this.onLoad, this);
13583 this.store.on('beforeload', this.onBeforeLoad, this);
13587 this.cells = this.el.select('.fc-day',true);
13588 //Roo.log(this.cells);
13589 this.textNodes = this.el.query('.fc-day-number');
13590 this.cells.addClassOnOver('fc-state-hover');
13592 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13593 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13594 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13595 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13597 this.on('monthchange', this.onMonthChange, this);
13599 this.update(new Date().clearTime());
13602 resize : function() {
13603 var sz = this.el.getSize();
13605 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13606 this.el.select('.fc-day-content div',true).setHeight(34);
13611 showPrevMonth : function(e){
13612 this.update(this.activeDate.add("mo", -1));
13614 showToday : function(e){
13615 this.update(new Date().clearTime());
13618 showNextMonth : function(e){
13619 this.update(this.activeDate.add("mo", 1));
13623 showPrevYear : function(){
13624 this.update(this.activeDate.add("y", -1));
13628 showNextYear : function(){
13629 this.update(this.activeDate.add("y", 1));
13634 update : function(date)
13636 var vd = this.activeDate;
13637 this.activeDate = date;
13638 // if(vd && this.el){
13639 // var t = date.getTime();
13640 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13641 // Roo.log('using add remove');
13643 // this.fireEvent('monthchange', this, date);
13645 // this.cells.removeClass("fc-state-highlight");
13646 // this.cells.each(function(c){
13647 // if(c.dateValue == t){
13648 // c.addClass("fc-state-highlight");
13649 // setTimeout(function(){
13650 // try{c.dom.firstChild.focus();}catch(e){}
13660 var days = date.getDaysInMonth();
13662 var firstOfMonth = date.getFirstDateOfMonth();
13663 var startingPos = firstOfMonth.getDay()-this.startDay;
13665 if(startingPos < this.startDay){
13669 var pm = date.add(Date.MONTH, -1);
13670 var prevStart = pm.getDaysInMonth()-startingPos;
13672 this.cells = this.el.select('.fc-day',true);
13673 this.textNodes = this.el.query('.fc-day-number');
13674 this.cells.addClassOnOver('fc-state-hover');
13676 var cells = this.cells.elements;
13677 var textEls = this.textNodes;
13679 Roo.each(cells, function(cell){
13680 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13683 days += startingPos;
13685 // convert everything to numbers so it's fast
13686 var day = 86400000;
13687 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13690 //Roo.log(prevStart);
13692 var today = new Date().clearTime().getTime();
13693 var sel = date.clearTime().getTime();
13694 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13695 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13696 var ddMatch = this.disabledDatesRE;
13697 var ddText = this.disabledDatesText;
13698 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13699 var ddaysText = this.disabledDaysText;
13700 var format = this.format;
13702 var setCellClass = function(cal, cell){
13706 //Roo.log('set Cell Class');
13708 var t = d.getTime();
13712 cell.dateValue = t;
13714 cell.className += " fc-today";
13715 cell.className += " fc-state-highlight";
13716 cell.title = cal.todayText;
13719 // disable highlight in other month..
13720 //cell.className += " fc-state-highlight";
13725 cell.className = " fc-state-disabled";
13726 cell.title = cal.minText;
13730 cell.className = " fc-state-disabled";
13731 cell.title = cal.maxText;
13735 if(ddays.indexOf(d.getDay()) != -1){
13736 cell.title = ddaysText;
13737 cell.className = " fc-state-disabled";
13740 if(ddMatch && format){
13741 var fvalue = d.dateFormat(format);
13742 if(ddMatch.test(fvalue)){
13743 cell.title = ddText.replace("%0", fvalue);
13744 cell.className = " fc-state-disabled";
13748 if (!cell.initialClassName) {
13749 cell.initialClassName = cell.dom.className;
13752 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13757 for(; i < startingPos; i++) {
13758 textEls[i].innerHTML = (++prevStart);
13759 d.setDate(d.getDate()+1);
13761 cells[i].className = "fc-past fc-other-month";
13762 setCellClass(this, cells[i]);
13767 for(; i < days; i++){
13768 intDay = i - startingPos + 1;
13769 textEls[i].innerHTML = (intDay);
13770 d.setDate(d.getDate()+1);
13772 cells[i].className = ''; // "x-date-active";
13773 setCellClass(this, cells[i]);
13777 for(; i < 42; i++) {
13778 textEls[i].innerHTML = (++extraDays);
13779 d.setDate(d.getDate()+1);
13781 cells[i].className = "fc-future fc-other-month";
13782 setCellClass(this, cells[i]);
13785 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13787 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13789 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13790 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13792 if(totalRows != 6){
13793 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13794 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13797 this.fireEvent('monthchange', this, date);
13801 if(!this.internalRender){
13802 var main = this.el.dom.firstChild;
13803 var w = main.offsetWidth;
13804 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13805 Roo.fly(main).setWidth(w);
13806 this.internalRender = true;
13807 // opera does not respect the auto grow header center column
13808 // then, after it gets a width opera refuses to recalculate
13809 // without a second pass
13810 if(Roo.isOpera && !this.secondPass){
13811 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13812 this.secondPass = true;
13813 this.update.defer(10, this, [date]);
13820 findCell : function(dt) {
13821 dt = dt.clearTime().getTime();
13823 this.cells.each(function(c){
13824 //Roo.log("check " +c.dateValue + '?=' + dt);
13825 if(c.dateValue == dt){
13835 findCells : function(ev) {
13836 var s = ev.start.clone().clearTime().getTime();
13838 var e= ev.end.clone().clearTime().getTime();
13841 this.cells.each(function(c){
13842 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13844 if(c.dateValue > e){
13847 if(c.dateValue < s){
13856 // findBestRow: function(cells)
13860 // for (var i =0 ; i < cells.length;i++) {
13861 // ret = Math.max(cells[i].rows || 0,ret);
13868 addItem : function(ev)
13870 // look for vertical location slot in
13871 var cells = this.findCells(ev);
13873 // ev.row = this.findBestRow(cells);
13875 // work out the location.
13879 for(var i =0; i < cells.length; i++) {
13881 cells[i].row = cells[0].row;
13884 cells[i].row = cells[i].row + 1;
13894 if (crow.start.getY() == cells[i].getY()) {
13896 crow.end = cells[i];
13913 cells[0].events.push(ev);
13915 this.calevents.push(ev);
13918 clearEvents: function() {
13920 if(!this.calevents){
13924 Roo.each(this.cells.elements, function(c){
13930 Roo.each(this.calevents, function(e) {
13931 Roo.each(e.els, function(el) {
13932 el.un('mouseenter' ,this.onEventEnter, this);
13933 el.un('mouseleave' ,this.onEventLeave, this);
13938 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13944 renderEvents: function()
13948 this.cells.each(function(c) {
13957 if(c.row != c.events.length){
13958 r = 4 - (4 - (c.row - c.events.length));
13961 c.events = ev.slice(0, r);
13962 c.more = ev.slice(r);
13964 if(c.more.length && c.more.length == 1){
13965 c.events.push(c.more.pop());
13968 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13972 this.cells.each(function(c) {
13974 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13977 for (var e = 0; e < c.events.length; e++){
13978 var ev = c.events[e];
13979 var rows = ev.rows;
13981 for(var i = 0; i < rows.length; i++) {
13983 // how many rows should it span..
13986 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13987 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13989 unselectable : "on",
13992 cls: 'fc-event-inner',
13996 // cls: 'fc-event-time',
13997 // html : cells.length > 1 ? '' : ev.time
14001 cls: 'fc-event-title',
14002 html : String.format('{0}', ev.title)
14009 cls: 'ui-resizable-handle ui-resizable-e',
14010 html : '  '
14017 cfg.cls += ' fc-event-start';
14019 if ((i+1) == rows.length) {
14020 cfg.cls += ' fc-event-end';
14023 var ctr = _this.el.select('.fc-event-container',true).first();
14024 var cg = ctr.createChild(cfg);
14026 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14027 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14029 var r = (c.more.length) ? 1 : 0;
14030 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14031 cg.setWidth(ebox.right - sbox.x -2);
14033 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14034 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14035 cg.on('click', _this.onEventClick, _this, ev);
14046 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14047 style : 'position: absolute',
14048 unselectable : "on",
14051 cls: 'fc-event-inner',
14055 cls: 'fc-event-title',
14063 cls: 'ui-resizable-handle ui-resizable-e',
14064 html : '  '
14070 var ctr = _this.el.select('.fc-event-container',true).first();
14071 var cg = ctr.createChild(cfg);
14073 var sbox = c.select('.fc-day-content',true).first().getBox();
14074 var ebox = c.select('.fc-day-content',true).first().getBox();
14076 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14077 cg.setWidth(ebox.right - sbox.x -2);
14079 cg.on('click', _this.onMoreEventClick, _this, c.more);
14089 onEventEnter: function (e, el,event,d) {
14090 this.fireEvent('evententer', this, el, event);
14093 onEventLeave: function (e, el,event,d) {
14094 this.fireEvent('eventleave', this, el, event);
14097 onEventClick: function (e, el,event,d) {
14098 this.fireEvent('eventclick', this, el, event);
14101 onMonthChange: function () {
14105 onMoreEventClick: function(e, el, more)
14109 this.calpopover.placement = 'right';
14110 this.calpopover.setTitle('More');
14112 this.calpopover.setContent('');
14114 var ctr = this.calpopover.el.select('.popover-content', true).first();
14116 Roo.each(more, function(m){
14118 cls : 'fc-event-hori fc-event-draggable',
14121 var cg = ctr.createChild(cfg);
14123 cg.on('click', _this.onEventClick, _this, m);
14126 this.calpopover.show(el);
14131 onLoad: function ()
14133 this.calevents = [];
14136 if(this.store.getCount() > 0){
14137 this.store.data.each(function(d){
14140 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14141 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14142 time : d.data.start_time,
14143 title : d.data.title,
14144 description : d.data.description,
14145 venue : d.data.venue
14150 this.renderEvents();
14152 if(this.calevents.length && this.loadMask){
14153 this.maskEl.hide();
14157 onBeforeLoad: function()
14159 this.clearEvents();
14161 this.maskEl.show();
14175 * @class Roo.bootstrap.Popover
14176 * @extends Roo.bootstrap.Component
14177 * Bootstrap Popover class
14178 * @cfg {String} html contents of the popover (or false to use children..)
14179 * @cfg {String} title of popover (or false to hide)
14180 * @cfg {String} placement how it is placed
14181 * @cfg {String} trigger click || hover (or false to trigger manually)
14182 * @cfg {String} over what (parent or false to trigger manually.)
14183 * @cfg {Number} delay - delay before showing
14186 * Create a new Popover
14187 * @param {Object} config The config object
14190 Roo.bootstrap.Popover = function(config){
14191 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14194 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14196 title: 'Fill in a title',
14199 placement : 'right',
14200 trigger : 'hover', // hover
14206 can_build_overlaid : false,
14208 getChildContainer : function()
14210 return this.el.select('.popover-content',true).first();
14213 getAutoCreate : function(){
14214 Roo.log('make popover?');
14216 cls : 'popover roo-dynamic',
14217 style: 'display:block',
14223 cls : 'popover-inner',
14227 cls: 'popover-title',
14231 cls : 'popover-content',
14242 setTitle: function(str)
14244 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14246 setContent: function(str)
14248 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14250 // as it get's added to the bottom of the page.
14251 onRender : function(ct, position)
14253 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14255 var cfg = Roo.apply({}, this.getAutoCreate());
14259 cfg.cls += ' ' + this.cls;
14262 cfg.style = this.style;
14264 Roo.log("adding to ")
14265 this.el = Roo.get(document.body).createChild(cfg, position);
14271 initEvents : function()
14273 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14274 this.el.enableDisplayMode('block');
14276 if (this.over === false) {
14279 if (this.triggers === false) {
14282 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14283 var triggers = this.trigger ? this.trigger.split(' ') : [];
14284 Roo.each(triggers, function(trigger) {
14286 if (trigger == 'click') {
14287 on_el.on('click', this.toggle, this);
14288 } else if (trigger != 'manual') {
14289 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14290 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14292 on_el.on(eventIn ,this.enter, this);
14293 on_el.on(eventOut, this.leave, this);
14304 toggle : function () {
14305 this.hoverState == 'in' ? this.leave() : this.enter();
14308 enter : function () {
14311 clearTimeout(this.timeout);
14313 this.hoverState = 'in';
14315 if (!this.delay || !this.delay.show) {
14320 this.timeout = setTimeout(function () {
14321 if (_t.hoverState == 'in') {
14324 }, this.delay.show)
14326 leave : function() {
14327 clearTimeout(this.timeout);
14329 this.hoverState = 'out';
14331 if (!this.delay || !this.delay.hide) {
14336 this.timeout = setTimeout(function () {
14337 if (_t.hoverState == 'out') {
14340 }, this.delay.hide)
14343 show : function (on_el)
14346 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14349 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14350 if (this.html !== false) {
14351 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14353 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14354 if (!this.title.length) {
14355 this.el.select('.popover-title',true).hide();
14358 var placement = typeof this.placement == 'function' ?
14359 this.placement.call(this, this.el, on_el) :
14362 var autoToken = /\s?auto?\s?/i;
14363 var autoPlace = autoToken.test(placement);
14365 placement = placement.replace(autoToken, '') || 'top';
14369 //this.el.setXY([0,0]);
14371 this.el.dom.style.display='block';
14372 this.el.addClass(placement);
14374 //this.el.appendTo(on_el);
14376 var p = this.getPosition();
14377 var box = this.el.getBox();
14382 var align = Roo.bootstrap.Popover.alignment[placement];
14383 this.el.alignTo(on_el, align[0],align[1]);
14384 //var arrow = this.el.select('.arrow',true).first();
14385 //arrow.set(align[2],
14387 this.el.addClass('in');
14388 this.hoverState = null;
14390 if (this.el.hasClass('fade')) {
14397 this.el.setXY([0,0]);
14398 this.el.removeClass('in');
14405 Roo.bootstrap.Popover.alignment = {
14406 'left' : ['r-l', [-10,0], 'right'],
14407 'right' : ['l-r', [10,0], 'left'],
14408 'bottom' : ['t-b', [0,10], 'top'],
14409 'top' : [ 'b-t', [0,-10], 'bottom']
14420 * @class Roo.bootstrap.Progress
14421 * @extends Roo.bootstrap.Component
14422 * Bootstrap Progress class
14423 * @cfg {Boolean} striped striped of the progress bar
14424 * @cfg {Boolean} active animated of the progress bar
14428 * Create a new Progress
14429 * @param {Object} config The config object
14432 Roo.bootstrap.Progress = function(config){
14433 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14436 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14441 getAutoCreate : function(){
14449 cfg.cls += ' progress-striped';
14453 cfg.cls += ' active';
14472 * @class Roo.bootstrap.ProgressBar
14473 * @extends Roo.bootstrap.Component
14474 * Bootstrap ProgressBar class
14475 * @cfg {Number} aria_valuenow aria-value now
14476 * @cfg {Number} aria_valuemin aria-value min
14477 * @cfg {Number} aria_valuemax aria-value max
14478 * @cfg {String} label label for the progress bar
14479 * @cfg {String} panel (success | info | warning | danger )
14480 * @cfg {String} role role of the progress bar
14481 * @cfg {String} sr_only text
14485 * Create a new ProgressBar
14486 * @param {Object} config The config object
14489 Roo.bootstrap.ProgressBar = function(config){
14490 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14493 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14497 aria_valuemax : 100,
14503 getAutoCreate : function()
14508 cls: 'progress-bar',
14509 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14521 cfg.role = this.role;
14524 if(this.aria_valuenow){
14525 cfg['aria-valuenow'] = this.aria_valuenow;
14528 if(this.aria_valuemin){
14529 cfg['aria-valuemin'] = this.aria_valuemin;
14532 if(this.aria_valuemax){
14533 cfg['aria-valuemax'] = this.aria_valuemax;
14536 if(this.label && !this.sr_only){
14537 cfg.html = this.label;
14541 cfg.cls += ' progress-bar-' + this.panel;
14547 update : function(aria_valuenow)
14549 this.aria_valuenow = aria_valuenow;
14551 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14566 * @class Roo.bootstrap.TabGroup
14567 * @extends Roo.bootstrap.Column
14568 * Bootstrap Column class
14569 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14570 * @cfg {Boolean} carousel true to make the group behave like a carousel
14571 * @cfg {Number} bullets show the panel pointer.. default 0
14572 * @cfg {Boolena} autoslide (true|false) auto slide .. default false
14573 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14576 * Create a new TabGroup
14577 * @param {Object} config The config object
14580 Roo.bootstrap.TabGroup = function(config){
14581 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14583 this.navId = Roo.id();
14586 Roo.bootstrap.TabGroup.register(this);
14590 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14593 transition : false,
14599 getAutoCreate : function()
14601 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14603 cfg.cls += ' tab-content';
14605 if (this.carousel) {
14606 cfg.cls += ' carousel slide';
14609 cls : 'carousel-inner'
14612 if(this.bullets > 0){
14615 cls : 'carousel-bullets',
14619 for (var i = 0; i < this.bullets; i++){
14621 cls : 'bullet bullet-' + i
14629 cfg.cn[0].cn = bullets;
14636 initEvents: function()
14638 Roo.log('-------- init events on tab group ---------');
14642 if(this.bullets > 0){
14644 for (var i = 0; i < this.bullets; i++){
14645 var bullet = this.el.select('.bullet-' + i, true).first();
14651 bullet.on('click', (function(e, el, o, ii, t){
14653 e.preventDefault();
14655 _this.showPanel(ii);
14657 }).createDelegate(this, [i, bullet], true));
14662 if(this.autoslide){
14663 this.slideFn = window.setInterval(function() {
14664 _this.showPanelNext();
14669 getChildContainer : function()
14671 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14675 * register a Navigation item
14676 * @param {Roo.bootstrap.NavItem} the navitem to add
14678 register : function(item)
14680 this.tabs.push( item);
14681 item.navId = this.navId; // not really needed..
14685 getActivePanel : function()
14688 Roo.each(this.tabs, function(t) {
14698 getPanelByName : function(n)
14701 Roo.each(this.tabs, function(t) {
14702 if (t.tabId == n) {
14710 indexOfPanel : function(p)
14713 Roo.each(this.tabs, function(t,i) {
14714 if (t.tabId == p.tabId) {
14723 * show a specific panel
14724 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14725 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14727 showPanel : function (pan)
14729 if(this.transition){
14730 Roo.log("waiting for the transitionend");
14734 if (typeof(pan) == 'number') {
14735 pan = this.tabs[pan];
14737 if (typeof(pan) == 'string') {
14738 pan = this.getPanelByName(pan);
14740 if (pan.tabId == this.getActivePanel().tabId) {
14743 var cur = this.getActivePanel();
14745 if (false === cur.fireEvent('beforedeactivate')) {
14749 if(this.bullets > 0){
14750 this.setActiveBullet(this.indexOfPanel(pan));
14753 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14755 this.transition = true;
14756 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14757 var lr = dir == 'next' ? 'left' : 'right';
14758 pan.el.addClass(dir); // or prev
14759 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14760 cur.el.addClass(lr); // or right
14761 pan.el.addClass(lr);
14764 cur.el.on('transitionend', function() {
14765 Roo.log("trans end?");
14767 pan.el.removeClass([lr,dir]);
14768 pan.setActive(true);
14770 cur.el.removeClass([lr]);
14771 cur.setActive(false);
14773 _this.transition = false;
14775 }, this, { single: true } );
14780 cur.setActive(false);
14781 pan.setActive(true);
14786 showPanelNext : function()
14788 var i = this.indexOfPanel(this.getActivePanel());
14790 if (i >= this.tabs.length - 1 && !this.autoslide) {
14794 if (i >= this.tabs.length - 1 && this.autoslide) {
14798 this.showPanel(this.tabs[i+1]);
14801 showPanelPrev : function()
14803 var i = this.indexOfPanel(this.getActivePanel());
14805 if (i < 1 && !this.autoslide) {
14809 if (i < 1 && this.autoslide) {
14810 i = this.tabs.length;
14813 this.showPanel(this.tabs[i-1]);
14816 setActiveBullet : function(i)
14818 Roo.each(this.el.select('.bullet', true).elements, function(el){
14819 el.removeClass('selected');
14822 var bullet = this.el.select('.bullet-' + i, true).first();
14828 bullet.addClass('selected');
14839 Roo.apply(Roo.bootstrap.TabGroup, {
14843 * register a Navigation Group
14844 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14846 register : function(navgrp)
14848 this.groups[navgrp.navId] = navgrp;
14852 * fetch a Navigation Group based on the navigation ID
14853 * if one does not exist , it will get created.
14854 * @param {string} the navgroup to add
14855 * @returns {Roo.bootstrap.NavGroup} the navgroup
14857 get: function(navId) {
14858 if (typeof(this.groups[navId]) == 'undefined') {
14859 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14861 return this.groups[navId] ;
14876 * @class Roo.bootstrap.TabPanel
14877 * @extends Roo.bootstrap.Component
14878 * Bootstrap TabPanel class
14879 * @cfg {Boolean} active panel active
14880 * @cfg {String} html panel content
14881 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14882 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14886 * Create a new TabPanel
14887 * @param {Object} config The config object
14890 Roo.bootstrap.TabPanel = function(config){
14891 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14895 * Fires when the active status changes
14896 * @param {Roo.bootstrap.TabPanel} this
14897 * @param {Boolean} state the new state
14902 * @event beforedeactivate
14903 * Fires before a tab is de-activated - can be used to do validation on a form.
14904 * @param {Roo.bootstrap.TabPanel} this
14905 * @return {Boolean} false if there is an error
14908 'beforedeactivate': true
14911 this.tabId = this.tabId || Roo.id();
14915 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14922 getAutoCreate : function(){
14925 // item is needed for carousel - not sure if it has any effect otherwise
14926 cls: 'tab-pane item',
14927 html: this.html || ''
14931 cfg.cls += ' active';
14935 cfg.tabId = this.tabId;
14942 initEvents: function()
14944 Roo.log('-------- init events on tab panel ---------');
14946 var p = this.parent();
14947 this.navId = this.navId || p.navId;
14949 if (typeof(this.navId) != 'undefined') {
14950 // not really needed.. but just in case.. parent should be a NavGroup.
14951 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14952 Roo.log(['register', tg, this]);
14955 var i = tg.tabs.length - 1;
14957 if(this.active && tg.bullets > 0 && i < tg.bullets){
14958 tg.setActiveBullet(i);
14965 onRender : function(ct, position)
14967 // Roo.log("Call onRender: " + this.xtype);
14969 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14977 setActive: function(state)
14979 Roo.log("panel - set active " + this.tabId + "=" + state);
14981 this.active = state;
14983 this.el.removeClass('active');
14985 } else if (!this.el.hasClass('active')) {
14986 this.el.addClass('active');
14989 this.fireEvent('changed', this, state);
15006 * @class Roo.bootstrap.DateField
15007 * @extends Roo.bootstrap.Input
15008 * Bootstrap DateField class
15009 * @cfg {Number} weekStart default 0
15010 * @cfg {String} viewMode default empty, (months|years)
15011 * @cfg {String} minViewMode default empty, (months|years)
15012 * @cfg {Number} startDate default -Infinity
15013 * @cfg {Number} endDate default Infinity
15014 * @cfg {Boolean} todayHighlight default false
15015 * @cfg {Boolean} todayBtn default false
15016 * @cfg {Boolean} calendarWeeks default false
15017 * @cfg {Object} daysOfWeekDisabled default empty
15018 * @cfg {Boolean} singleMode default false (true | false)
15020 * @cfg {Boolean} keyboardNavigation default true
15021 * @cfg {String} language default en
15024 * Create a new DateField
15025 * @param {Object} config The config object
15028 Roo.bootstrap.DateField = function(config){
15029 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15033 * Fires when this field show.
15034 * @param {Roo.bootstrap.DateField} this
15035 * @param {Mixed} date The date value
15040 * Fires when this field hide.
15041 * @param {Roo.bootstrap.DateField} this
15042 * @param {Mixed} date The date value
15047 * Fires when select a date.
15048 * @param {Roo.bootstrap.DateField} this
15049 * @param {Mixed} date The date value
15055 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15058 * @cfg {String} format
15059 * The default date format string which can be overriden for localization support. The format must be
15060 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15064 * @cfg {String} altFormats
15065 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15066 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15068 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15076 todayHighlight : false,
15082 keyboardNavigation: true,
15084 calendarWeeks: false,
15086 startDate: -Infinity,
15090 daysOfWeekDisabled: [],
15094 singleMode : false,
15096 UTCDate: function()
15098 return new Date(Date.UTC.apply(Date, arguments));
15101 UTCToday: function()
15103 var today = new Date();
15104 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15107 getDate: function() {
15108 var d = this.getUTCDate();
15109 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15112 getUTCDate: function() {
15116 setDate: function(d) {
15117 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15120 setUTCDate: function(d) {
15122 this.setValue(this.formatDate(this.date));
15125 onRender: function(ct, position)
15128 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15130 this.language = this.language || 'en';
15131 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15132 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15134 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15135 this.format = this.format || 'm/d/y';
15136 this.isInline = false;
15137 this.isInput = true;
15138 this.component = this.el.select('.add-on', true).first() || false;
15139 this.component = (this.component && this.component.length === 0) ? false : this.component;
15140 this.hasInput = this.component && this.inputEL().length;
15142 if (typeof(this.minViewMode === 'string')) {
15143 switch (this.minViewMode) {
15145 this.minViewMode = 1;
15148 this.minViewMode = 2;
15151 this.minViewMode = 0;
15156 if (typeof(this.viewMode === 'string')) {
15157 switch (this.viewMode) {
15170 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15172 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15174 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15176 this.picker().on('mousedown', this.onMousedown, this);
15177 this.picker().on('click', this.onClick, this);
15179 this.picker().addClass('datepicker-dropdown');
15181 this.startViewMode = this.viewMode;
15183 if(this.singleMode){
15184 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15185 v.setVisibilityMode(Roo.Element.DISPLAY)
15189 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15190 v.setStyle('width', '189px');
15194 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15195 if(!this.calendarWeeks){
15200 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15201 v.attr('colspan', function(i, val){
15202 return parseInt(val) + 1;
15207 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15209 this.setStartDate(this.startDate);
15210 this.setEndDate(this.endDate);
15212 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15219 if(this.isInline) {
15224 picker : function()
15226 return this.pickerEl;
15227 // return this.el.select('.datepicker', true).first();
15230 fillDow: function()
15232 var dowCnt = this.weekStart;
15241 if(this.calendarWeeks){
15249 while (dowCnt < this.weekStart + 7) {
15253 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15257 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15260 fillMonths: function()
15263 var months = this.picker().select('>.datepicker-months td', true).first();
15265 months.dom.innerHTML = '';
15271 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15274 months.createChild(month);
15281 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;
15283 if (this.date < this.startDate) {
15284 this.viewDate = new Date(this.startDate);
15285 } else if (this.date > this.endDate) {
15286 this.viewDate = new Date(this.endDate);
15288 this.viewDate = new Date(this.date);
15296 var d = new Date(this.viewDate),
15297 year = d.getUTCFullYear(),
15298 month = d.getUTCMonth(),
15299 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15300 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15301 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15302 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15303 currentDate = this.date && this.date.valueOf(),
15304 today = this.UTCToday();
15306 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15308 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15310 // this.picker.select('>tfoot th.today').
15311 // .text(dates[this.language].today)
15312 // .toggle(this.todayBtn !== false);
15314 this.updateNavArrows();
15317 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15319 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15321 prevMonth.setUTCDate(day);
15323 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15325 var nextMonth = new Date(prevMonth);
15327 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15329 nextMonth = nextMonth.valueOf();
15331 var fillMonths = false;
15333 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15335 while(prevMonth.valueOf() < nextMonth) {
15338 if (prevMonth.getUTCDay() === this.weekStart) {
15340 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15348 if(this.calendarWeeks){
15349 // ISO 8601: First week contains first thursday.
15350 // ISO also states week starts on Monday, but we can be more abstract here.
15352 // Start of current week: based on weekstart/current date
15353 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15354 // Thursday of this week
15355 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15356 // First Thursday of year, year from thursday
15357 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15358 // Calendar week: ms between thursdays, div ms per day, div 7 days
15359 calWeek = (th - yth) / 864e5 / 7 + 1;
15361 fillMonths.cn.push({
15369 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15371 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15374 if (this.todayHighlight &&
15375 prevMonth.getUTCFullYear() == today.getFullYear() &&
15376 prevMonth.getUTCMonth() == today.getMonth() &&
15377 prevMonth.getUTCDate() == today.getDate()) {
15378 clsName += ' today';
15381 if (currentDate && prevMonth.valueOf() === currentDate) {
15382 clsName += ' active';
15385 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15386 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15387 clsName += ' disabled';
15390 fillMonths.cn.push({
15392 cls: 'day ' + clsName,
15393 html: prevMonth.getDate()
15396 prevMonth.setDate(prevMonth.getDate()+1);
15399 var currentYear = this.date && this.date.getUTCFullYear();
15400 var currentMonth = this.date && this.date.getUTCMonth();
15402 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15404 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15405 v.removeClass('active');
15407 if(currentYear === year && k === currentMonth){
15408 v.addClass('active');
15411 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15412 v.addClass('disabled');
15418 year = parseInt(year/10, 10) * 10;
15420 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15422 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15425 for (var i = -1; i < 11; i++) {
15426 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15428 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15436 showMode: function(dir)
15439 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15442 Roo.each(this.picker().select('>div',true).elements, function(v){
15443 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15446 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15451 if(this.isInline) return;
15453 this.picker().removeClass(['bottom', 'top']);
15455 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15457 * place to the top of element!
15461 this.picker().addClass('top');
15462 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15467 this.picker().addClass('bottom');
15469 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15472 parseDate : function(value)
15474 if(!value || value instanceof Date){
15477 var v = Date.parseDate(value, this.format);
15478 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15479 v = Date.parseDate(value, 'Y-m-d');
15481 if(!v && this.altFormats){
15482 if(!this.altFormatsArray){
15483 this.altFormatsArray = this.altFormats.split("|");
15485 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15486 v = Date.parseDate(value, this.altFormatsArray[i]);
15492 formatDate : function(date, fmt)
15494 return (!date || !(date instanceof Date)) ?
15495 date : date.dateFormat(fmt || this.format);
15498 onFocus : function()
15500 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15504 onBlur : function()
15506 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15508 var d = this.inputEl().getValue();
15517 this.picker().show();
15521 this.fireEvent('show', this, this.date);
15526 if(this.isInline) return;
15527 this.picker().hide();
15528 this.viewMode = this.startViewMode;
15531 this.fireEvent('hide', this, this.date);
15535 onMousedown: function(e)
15537 e.stopPropagation();
15538 e.preventDefault();
15543 Roo.bootstrap.DateField.superclass.keyup.call(this);
15547 setValue: function(v)
15550 // v can be a string or a date..
15553 var d = new Date(this.parseDate(v) ).clearTime();
15555 if(isNaN(d.getTime())){
15556 this.date = this.viewDate = '';
15557 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15561 v = this.formatDate(d);
15563 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15565 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15569 this.fireEvent('select', this, this.date);
15573 getValue: function()
15575 return this.formatDate(this.date);
15578 fireKey: function(e)
15580 if (!this.picker().isVisible()){
15581 if (e.keyCode == 27) // allow escape to hide and re-show picker
15586 var dateChanged = false,
15588 newDate, newViewDate;
15593 e.preventDefault();
15597 if (!this.keyboardNavigation) break;
15598 dir = e.keyCode == 37 ? -1 : 1;
15601 newDate = this.moveYear(this.date, dir);
15602 newViewDate = this.moveYear(this.viewDate, dir);
15603 } else if (e.shiftKey){
15604 newDate = this.moveMonth(this.date, dir);
15605 newViewDate = this.moveMonth(this.viewDate, dir);
15607 newDate = new Date(this.date);
15608 newDate.setUTCDate(this.date.getUTCDate() + dir);
15609 newViewDate = new Date(this.viewDate);
15610 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15612 if (this.dateWithinRange(newDate)){
15613 this.date = newDate;
15614 this.viewDate = newViewDate;
15615 this.setValue(this.formatDate(this.date));
15617 e.preventDefault();
15618 dateChanged = true;
15623 if (!this.keyboardNavigation) break;
15624 dir = e.keyCode == 38 ? -1 : 1;
15626 newDate = this.moveYear(this.date, dir);
15627 newViewDate = this.moveYear(this.viewDate, dir);
15628 } else if (e.shiftKey){
15629 newDate = this.moveMonth(this.date, dir);
15630 newViewDate = this.moveMonth(this.viewDate, dir);
15632 newDate = new Date(this.date);
15633 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15634 newViewDate = new Date(this.viewDate);
15635 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15637 if (this.dateWithinRange(newDate)){
15638 this.date = newDate;
15639 this.viewDate = newViewDate;
15640 this.setValue(this.formatDate(this.date));
15642 e.preventDefault();
15643 dateChanged = true;
15647 this.setValue(this.formatDate(this.date));
15649 e.preventDefault();
15652 this.setValue(this.formatDate(this.date));
15666 onClick: function(e)
15668 e.stopPropagation();
15669 e.preventDefault();
15671 var target = e.getTarget();
15673 if(target.nodeName.toLowerCase() === 'i'){
15674 target = Roo.get(target).dom.parentNode;
15677 var nodeName = target.nodeName;
15678 var className = target.className;
15679 var html = target.innerHTML;
15680 //Roo.log(nodeName);
15682 switch(nodeName.toLowerCase()) {
15684 switch(className) {
15690 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15691 switch(this.viewMode){
15693 this.viewDate = this.moveMonth(this.viewDate, dir);
15697 this.viewDate = this.moveYear(this.viewDate, dir);
15703 var date = new Date();
15704 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15706 this.setValue(this.formatDate(this.date));
15713 if (className.indexOf('disabled') < 0) {
15714 this.viewDate.setUTCDate(1);
15715 if (className.indexOf('month') > -1) {
15716 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15718 var year = parseInt(html, 10) || 0;
15719 this.viewDate.setUTCFullYear(year);
15723 if(this.singleMode){
15724 this.setValue(this.formatDate(this.viewDate));
15735 //Roo.log(className);
15736 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15737 var day = parseInt(html, 10) || 1;
15738 var year = this.viewDate.getUTCFullYear(),
15739 month = this.viewDate.getUTCMonth();
15741 if (className.indexOf('old') > -1) {
15748 } else if (className.indexOf('new') > -1) {
15756 //Roo.log([year,month,day]);
15757 this.date = this.UTCDate(year, month, day,0,0,0,0);
15758 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15760 //Roo.log(this.formatDate(this.date));
15761 this.setValue(this.formatDate(this.date));
15768 setStartDate: function(startDate)
15770 this.startDate = startDate || -Infinity;
15771 if (this.startDate !== -Infinity) {
15772 this.startDate = this.parseDate(this.startDate);
15775 this.updateNavArrows();
15778 setEndDate: function(endDate)
15780 this.endDate = endDate || Infinity;
15781 if (this.endDate !== Infinity) {
15782 this.endDate = this.parseDate(this.endDate);
15785 this.updateNavArrows();
15788 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15790 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15791 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15792 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15794 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15795 return parseInt(d, 10);
15798 this.updateNavArrows();
15801 updateNavArrows: function()
15803 if(this.singleMode){
15807 var d = new Date(this.viewDate),
15808 year = d.getUTCFullYear(),
15809 month = d.getUTCMonth();
15811 Roo.each(this.picker().select('.prev', true).elements, function(v){
15813 switch (this.viewMode) {
15816 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15822 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15829 Roo.each(this.picker().select('.next', true).elements, function(v){
15831 switch (this.viewMode) {
15834 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15840 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15848 moveMonth: function(date, dir)
15850 if (!dir) return date;
15851 var new_date = new Date(date.valueOf()),
15852 day = new_date.getUTCDate(),
15853 month = new_date.getUTCMonth(),
15854 mag = Math.abs(dir),
15856 dir = dir > 0 ? 1 : -1;
15859 // If going back one month, make sure month is not current month
15860 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15862 return new_date.getUTCMonth() == month;
15864 // If going forward one month, make sure month is as expected
15865 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15867 return new_date.getUTCMonth() != new_month;
15869 new_month = month + dir;
15870 new_date.setUTCMonth(new_month);
15871 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15872 if (new_month < 0 || new_month > 11)
15873 new_month = (new_month + 12) % 12;
15875 // For magnitudes >1, move one month at a time...
15876 for (var i=0; i<mag; i++)
15877 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15878 new_date = this.moveMonth(new_date, dir);
15879 // ...then reset the day, keeping it in the new month
15880 new_month = new_date.getUTCMonth();
15881 new_date.setUTCDate(day);
15883 return new_month != new_date.getUTCMonth();
15886 // Common date-resetting loop -- if date is beyond end of month, make it
15889 new_date.setUTCDate(--day);
15890 new_date.setUTCMonth(new_month);
15895 moveYear: function(date, dir)
15897 return this.moveMonth(date, dir*12);
15900 dateWithinRange: function(date)
15902 return date >= this.startDate && date <= this.endDate;
15908 this.picker().remove();
15913 Roo.apply(Roo.bootstrap.DateField, {
15924 html: '<i class="fa fa-arrow-left"/>'
15934 html: '<i class="fa fa-arrow-right"/>'
15976 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15977 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15978 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15979 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15980 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15993 navFnc: 'FullYear',
15998 navFnc: 'FullYear',
16003 Roo.apply(Roo.bootstrap.DateField, {
16007 cls: 'datepicker dropdown-menu roo-dynamic',
16011 cls: 'datepicker-days',
16015 cls: 'table-condensed',
16017 Roo.bootstrap.DateField.head,
16021 Roo.bootstrap.DateField.footer
16028 cls: 'datepicker-months',
16032 cls: 'table-condensed',
16034 Roo.bootstrap.DateField.head,
16035 Roo.bootstrap.DateField.content,
16036 Roo.bootstrap.DateField.footer
16043 cls: 'datepicker-years',
16047 cls: 'table-condensed',
16049 Roo.bootstrap.DateField.head,
16050 Roo.bootstrap.DateField.content,
16051 Roo.bootstrap.DateField.footer
16070 * @class Roo.bootstrap.TimeField
16071 * @extends Roo.bootstrap.Input
16072 * Bootstrap DateField class
16076 * Create a new TimeField
16077 * @param {Object} config The config object
16080 Roo.bootstrap.TimeField = function(config){
16081 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16085 * Fires when this field show.
16086 * @param {Roo.bootstrap.DateField} thisthis
16087 * @param {Mixed} date The date value
16092 * Fires when this field hide.
16093 * @param {Roo.bootstrap.DateField} this
16094 * @param {Mixed} date The date value
16099 * Fires when select a date.
16100 * @param {Roo.bootstrap.DateField} this
16101 * @param {Mixed} date The date value
16107 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16110 * @cfg {String} format
16111 * The default time format string which can be overriden for localization support. The format must be
16112 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16116 onRender: function(ct, position)
16119 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16121 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16123 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16125 this.pop = this.picker().select('>.datepicker-time',true).first();
16126 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16128 this.picker().on('mousedown', this.onMousedown, this);
16129 this.picker().on('click', this.onClick, this);
16131 this.picker().addClass('datepicker-dropdown');
16136 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16137 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16138 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16139 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16140 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16141 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16145 fireKey: function(e){
16146 if (!this.picker().isVisible()){
16147 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16153 e.preventDefault();
16161 this.onTogglePeriod();
16164 this.onIncrementMinutes();
16167 this.onDecrementMinutes();
16176 onClick: function(e) {
16177 e.stopPropagation();
16178 e.preventDefault();
16181 picker : function()
16183 return this.el.select('.datepicker', true).first();
16186 fillTime: function()
16188 var time = this.pop.select('tbody', true).first();
16190 time.dom.innerHTML = '';
16205 cls: 'hours-up glyphicon glyphicon-chevron-up'
16225 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16246 cls: 'timepicker-hour',
16261 cls: 'timepicker-minute',
16276 cls: 'btn btn-primary period',
16298 cls: 'hours-down glyphicon glyphicon-chevron-down'
16318 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16336 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16343 var hours = this.time.getHours();
16344 var minutes = this.time.getMinutes();
16357 hours = hours - 12;
16361 hours = '0' + hours;
16365 minutes = '0' + minutes;
16368 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16369 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16370 this.pop.select('button', true).first().dom.innerHTML = period;
16376 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16378 var cls = ['bottom'];
16380 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16387 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16392 this.picker().addClass(cls.join('-'));
16396 Roo.each(cls, function(c){
16398 _this.picker().setTop(_this.inputEl().getHeight());
16402 _this.picker().setTop(0 - _this.picker().getHeight());
16407 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16411 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16418 onFocus : function()
16420 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16424 onBlur : function()
16426 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16432 this.picker().show();
16437 this.fireEvent('show', this, this.date);
16442 this.picker().hide();
16445 this.fireEvent('hide', this, this.date);
16448 setTime : function()
16451 this.setValue(this.time.format(this.format));
16453 this.fireEvent('select', this, this.date);
16458 onMousedown: function(e){
16459 e.stopPropagation();
16460 e.preventDefault();
16463 onIncrementHours: function()
16465 Roo.log('onIncrementHours');
16466 this.time = this.time.add(Date.HOUR, 1);
16471 onDecrementHours: function()
16473 Roo.log('onDecrementHours');
16474 this.time = this.time.add(Date.HOUR, -1);
16478 onIncrementMinutes: function()
16480 Roo.log('onIncrementMinutes');
16481 this.time = this.time.add(Date.MINUTE, 1);
16485 onDecrementMinutes: function()
16487 Roo.log('onDecrementMinutes');
16488 this.time = this.time.add(Date.MINUTE, -1);
16492 onTogglePeriod: function()
16494 Roo.log('onTogglePeriod');
16495 this.time = this.time.add(Date.HOUR, 12);
16502 Roo.apply(Roo.bootstrap.TimeField, {
16532 cls: 'btn btn-info ok',
16544 Roo.apply(Roo.bootstrap.TimeField, {
16548 cls: 'datepicker dropdown-menu',
16552 cls: 'datepicker-time',
16556 cls: 'table-condensed',
16558 Roo.bootstrap.TimeField.content,
16559 Roo.bootstrap.TimeField.footer
16578 * @class Roo.bootstrap.MonthField
16579 * @extends Roo.bootstrap.Input
16580 * Bootstrap MonthField class
16582 * @cfg {String} language default en
16585 * Create a new MonthField
16586 * @param {Object} config The config object
16589 Roo.bootstrap.MonthField = function(config){
16590 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16595 * Fires when this field show.
16596 * @param {Roo.bootstrap.MonthField} this
16597 * @param {Mixed} date The date value
16602 * Fires when this field hide.
16603 * @param {Roo.bootstrap.MonthField} this
16604 * @param {Mixed} date The date value
16609 * Fires when select a date.
16610 * @param {Roo.bootstrap.MonthField} this
16611 * @param {String} oldvalue The old value
16612 * @param {String} newvalue The new value
16618 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16620 onRender: function(ct, position)
16623 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16625 this.language = this.language || 'en';
16626 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16627 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16629 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16630 this.isInline = false;
16631 this.isInput = true;
16632 this.component = this.el.select('.add-on', true).first() || false;
16633 this.component = (this.component && this.component.length === 0) ? false : this.component;
16634 this.hasInput = this.component && this.inputEL().length;
16636 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16638 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16640 this.picker().on('mousedown', this.onMousedown, this);
16641 this.picker().on('click', this.onClick, this);
16643 this.picker().addClass('datepicker-dropdown');
16645 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16646 v.setStyle('width', '189px');
16653 if(this.isInline) {
16659 setValue: function(v, suppressEvent)
16661 var o = this.getValue();
16663 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16667 if(suppressEvent !== true){
16668 this.fireEvent('select', this, o, v);
16673 getValue: function()
16678 onClick: function(e)
16680 e.stopPropagation();
16681 e.preventDefault();
16683 var target = e.getTarget();
16685 if(target.nodeName.toLowerCase() === 'i'){
16686 target = Roo.get(target).dom.parentNode;
16689 var nodeName = target.nodeName;
16690 var className = target.className;
16691 var html = target.innerHTML;
16693 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16697 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16699 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16705 picker : function()
16707 return this.pickerEl;
16710 fillMonths: function()
16713 var months = this.picker().select('>.datepicker-months td', true).first();
16715 months.dom.innerHTML = '';
16721 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16724 months.createChild(month);
16733 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16734 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16737 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16738 e.removeClass('active');
16740 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16741 e.addClass('active');
16748 if(this.isInline) return;
16750 this.picker().removeClass(['bottom', 'top']);
16752 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16754 * place to the top of element!
16758 this.picker().addClass('top');
16759 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16764 this.picker().addClass('bottom');
16766 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16769 onFocus : function()
16771 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16775 onBlur : function()
16777 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16779 var d = this.inputEl().getValue();
16788 this.picker().show();
16789 this.picker().select('>.datepicker-months', true).first().show();
16793 this.fireEvent('show', this, this.date);
16798 if(this.isInline) return;
16799 this.picker().hide();
16800 this.fireEvent('hide', this, this.date);
16804 onMousedown: function(e)
16806 e.stopPropagation();
16807 e.preventDefault();
16812 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16816 fireKey: function(e)
16818 if (!this.picker().isVisible()){
16819 if (e.keyCode == 27) // allow escape to hide and re-show picker
16829 e.preventDefault();
16833 dir = e.keyCode == 37 ? -1 : 1;
16835 this.vIndex = this.vIndex + dir;
16837 if(this.vIndex < 0){
16841 if(this.vIndex > 11){
16845 if(isNaN(this.vIndex)){
16849 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16855 dir = e.keyCode == 38 ? -1 : 1;
16857 this.vIndex = this.vIndex + dir * 4;
16859 if(this.vIndex < 0){
16863 if(this.vIndex > 11){
16867 if(isNaN(this.vIndex)){
16871 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16876 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16877 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16881 e.preventDefault();
16884 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16885 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16901 this.picker().remove();
16906 Roo.apply(Roo.bootstrap.MonthField, {
16925 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16926 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16931 Roo.apply(Roo.bootstrap.MonthField, {
16935 cls: 'datepicker dropdown-menu roo-dynamic',
16939 cls: 'datepicker-months',
16943 cls: 'table-condensed',
16945 Roo.bootstrap.DateField.content
16965 * @class Roo.bootstrap.CheckBox
16966 * @extends Roo.bootstrap.Input
16967 * Bootstrap CheckBox class
16969 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16970 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16971 * @cfg {String} boxLabel The text that appears beside the checkbox
16972 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16973 * @cfg {Boolean} checked initnal the element
16974 * @cfg {Boolean} inline inline the element (default false)
16975 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16978 * Create a new CheckBox
16979 * @param {Object} config The config object
16982 Roo.bootstrap.CheckBox = function(config){
16983 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16988 * Fires when the element is checked or unchecked.
16989 * @param {Roo.bootstrap.CheckBox} this This input
16990 * @param {Boolean} checked The new checked value
16997 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16999 inputType: 'checkbox',
17007 getAutoCreate : function()
17009 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17015 cfg.cls = 'form-group ' + this.inputType; //input-group
17018 cfg.cls += ' ' + this.inputType + '-inline';
17024 type : this.inputType,
17025 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17026 cls : 'roo-' + this.inputType, //'form-box',
17027 placeholder : this.placeholder || ''
17031 if (this.weight) { // Validity check?
17032 cfg.cls += " " + this.inputType + "-" + this.weight;
17035 if (this.disabled) {
17036 input.disabled=true;
17040 input.checked = this.checked;
17044 input.name = this.name;
17048 input.cls += ' input-' + this.size;
17053 ['xs','sm','md','lg'].map(function(size){
17054 if (settings[size]) {
17055 cfg.cls += ' col-' + size + '-' + settings[size];
17059 var inputblock = input;
17061 if (this.before || this.after) {
17064 cls : 'input-group',
17069 inputblock.cn.push({
17071 cls : 'input-group-addon',
17076 inputblock.cn.push(input);
17079 inputblock.cn.push({
17081 cls : 'input-group-addon',
17088 if (align ==='left' && this.fieldLabel.length) {
17089 Roo.log("left and has label");
17095 cls : 'control-label col-md-' + this.labelWidth,
17096 html : this.fieldLabel
17100 cls : "col-md-" + (12 - this.labelWidth),
17107 } else if ( this.fieldLabel.length) {
17112 tag: this.boxLabel ? 'span' : 'label',
17114 cls: 'control-label box-input-label',
17115 //cls : 'input-group-addon',
17116 html : this.fieldLabel
17126 Roo.log(" no label && no align");
17127 cfg.cn = [ inputblock ] ;
17132 var boxLabelCfg = {
17134 //'for': id, // box label is handled by onclick - so no for...
17136 html: this.boxLabel
17140 boxLabelCfg.tooltip = this.tooltip;
17143 cfg.cn.push(boxLabelCfg);
17153 * return the real input element.
17155 inputEl: function ()
17157 return this.el.select('input.roo-' + this.inputType,true).first();
17160 labelEl: function()
17162 return this.el.select('label.control-label',true).first();
17164 /* depricated... */
17168 return this.labelEl();
17171 initEvents : function()
17173 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17175 this.inputEl().on('click', this.onClick, this);
17177 if (this.boxLabel) {
17178 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17181 this.startValue = this.getValue();
17184 Roo.bootstrap.CheckBox.register(this);
17188 onClick : function()
17190 this.setChecked(!this.checked);
17193 setChecked : function(state,suppressEvent)
17195 this.startValue = this.getValue();
17197 if(this.inputType == 'radio'){
17199 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17200 e.dom.checked = false;
17203 this.inputEl().dom.checked = true;
17205 this.inputEl().dom.value = this.inputValue;
17207 if(suppressEvent !== true){
17208 this.fireEvent('check', this, true);
17216 this.checked = state;
17218 this.inputEl().dom.checked = state;
17220 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17222 if(suppressEvent !== true){
17223 this.fireEvent('check', this, state);
17229 getValue : function()
17231 if(this.inputType == 'radio'){
17232 return this.getGroupValue();
17235 return this.inputEl().getValue();
17239 getGroupValue : function()
17241 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17245 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17248 setValue : function(v,suppressEvent)
17250 if(this.inputType == 'radio'){
17251 this.setGroupValue(v, suppressEvent);
17255 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17260 setGroupValue : function(v, suppressEvent)
17262 this.startValue = this.getValue();
17264 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17265 e.dom.checked = false;
17267 if(e.dom.value == v){
17268 e.dom.checked = true;
17272 if(suppressEvent !== true){
17273 this.fireEvent('check', this, true);
17281 validate : function()
17285 (this.inputType == 'radio' && this.validateRadio()) ||
17286 (this.inputType == 'checkbox' && this.validateCheckbox())
17292 this.markInvalid();
17296 validateRadio : function()
17300 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17301 if(!e.dom.checked){
17313 validateCheckbox : function()
17316 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17319 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17327 for(var i in group){
17332 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17339 * Mark this field as valid
17341 markValid : function()
17343 if(this.allowBlank){
17349 this.fireEvent('valid', this);
17351 if(this.inputType == 'radio'){
17352 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17353 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17354 e.findParent('.form-group', false, true).addClass(_this.validClass);
17361 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17362 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17366 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17372 for(var i in group){
17373 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17374 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17379 * Mark this field as invalid
17380 * @param {String} msg The validation message
17382 markInvalid : function(msg)
17384 if(this.allowBlank){
17390 this.fireEvent('invalid', this, msg);
17392 if(this.inputType == 'radio'){
17393 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17394 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17395 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17402 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17403 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17407 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17413 for(var i in group){
17414 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17415 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17422 Roo.apply(Roo.bootstrap.CheckBox, {
17427 * register a CheckBox Group
17428 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17430 register : function(checkbox)
17432 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17433 this.groups[checkbox.groupId] = {};
17436 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17440 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17444 * fetch a CheckBox Group based on the group ID
17445 * @param {string} the group ID
17446 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17448 get: function(groupId) {
17449 if (typeof(this.groups[groupId]) == 'undefined') {
17453 return this.groups[groupId] ;
17465 *<div class="radio">
17467 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17468 Option one is this and that—be sure to include why it's great
17475 *<label class="radio-inline">fieldLabel</label>
17476 *<label class="radio-inline">
17477 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17485 * @class Roo.bootstrap.Radio
17486 * @extends Roo.bootstrap.CheckBox
17487 * Bootstrap Radio class
17490 * Create a new Radio
17491 * @param {Object} config The config object
17494 Roo.bootstrap.Radio = function(config){
17495 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17499 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17501 inputType: 'radio',
17505 getAutoCreate : function()
17507 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17508 align = align || 'left'; // default...
17515 tag : this.inline ? 'span' : 'div',
17520 var inline = this.inline ? ' radio-inline' : '';
17524 // does not need for, as we wrap the input with it..
17526 cls : 'control-label box-label' + inline,
17529 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17533 //cls : 'control-label' + inline,
17534 html : this.fieldLabel,
17535 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17544 type : this.inputType,
17545 //value : (!this.checked) ? this.valueOff : this.inputValue,
17546 value : this.inputValue,
17548 placeholder : this.placeholder || '' // ?? needed????
17551 if (this.weight) { // Validity check?
17552 input.cls += " radio-" + this.weight;
17554 if (this.disabled) {
17555 input.disabled=true;
17559 input.checked = this.checked;
17563 input.name = this.name;
17567 input.cls += ' input-' + this.size;
17570 //?? can span's inline have a width??
17573 ['xs','sm','md','lg'].map(function(size){
17574 if (settings[size]) {
17575 cfg.cls += ' col-' + size + '-' + settings[size];
17579 var inputblock = input;
17581 if (this.before || this.after) {
17584 cls : 'input-group',
17589 inputblock.cn.push({
17591 cls : 'input-group-addon',
17595 inputblock.cn.push(input);
17597 inputblock.cn.push({
17599 cls : 'input-group-addon',
17607 if (this.fieldLabel && this.fieldLabel.length) {
17608 cfg.cn.push(fieldLabel);
17611 // normal bootstrap puts the input inside the label.
17612 // however with our styled version - it has to go after the input.
17614 //lbl.cn.push(inputblock);
17618 cls: 'radio' + inline,
17625 cfg.cn.push( lblwrap);
17630 html: this.boxLabel
17639 initEvents : function()
17641 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17643 this.inputEl().on('click', this.onClick, this);
17644 if (this.boxLabel) {
17645 Roo.log('find label')
17646 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17651 inputEl: function ()
17653 return this.el.select('input.roo-radio',true).first();
17655 onClick : function()
17658 this.setChecked(true);
17661 setChecked : function(state,suppressEvent)
17664 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17665 v.dom.checked = false;
17668 Roo.log(this.inputEl().dom);
17669 this.checked = state;
17670 this.inputEl().dom.checked = state;
17672 if(suppressEvent !== true){
17673 this.fireEvent('check', this, state);
17676 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17680 getGroupValue : function()
17683 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17684 if(v.dom.checked == true){
17685 value = v.dom.value;
17693 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17694 * @return {Mixed} value The field value
17696 getValue : function(){
17697 return this.getGroupValue();
17703 //<script type="text/javascript">
17706 * Based Ext JS Library 1.1.1
17707 * Copyright(c) 2006-2007, Ext JS, LLC.
17713 * @class Roo.HtmlEditorCore
17714 * @extends Roo.Component
17715 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17717 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17720 Roo.HtmlEditorCore = function(config){
17723 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17728 * @event initialize
17729 * Fires when the editor is fully initialized (including the iframe)
17730 * @param {Roo.HtmlEditorCore} this
17735 * Fires when the editor is first receives the focus. Any insertion must wait
17736 * until after this event.
17737 * @param {Roo.HtmlEditorCore} this
17741 * @event beforesync
17742 * Fires before the textarea is updated with content from the editor iframe. Return false
17743 * to cancel the sync.
17744 * @param {Roo.HtmlEditorCore} this
17745 * @param {String} html
17749 * @event beforepush
17750 * Fires before the iframe editor is updated with content from the textarea. Return false
17751 * to cancel the push.
17752 * @param {Roo.HtmlEditorCore} this
17753 * @param {String} html
17758 * Fires when the textarea is updated with content from the editor iframe.
17759 * @param {Roo.HtmlEditorCore} this
17760 * @param {String} html
17765 * Fires when the iframe editor is updated with content from the textarea.
17766 * @param {Roo.HtmlEditorCore} this
17767 * @param {String} html
17772 * @event editorevent
17773 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17774 * @param {Roo.HtmlEditorCore} this
17780 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17782 // defaults : white / black...
17783 this.applyBlacklists();
17790 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17794 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17800 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17805 * @cfg {Number} height (in pixels)
17809 * @cfg {Number} width (in pixels)
17814 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17817 stylesheets: false,
17822 // private properties
17823 validationEvent : false,
17825 initialized : false,
17827 sourceEditMode : false,
17828 onFocus : Roo.emptyFn,
17830 hideMode:'offsets',
17834 // blacklist + whitelisted elements..
17841 * Protected method that will not generally be called directly. It
17842 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17843 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17845 getDocMarkup : function(){
17849 // inherit styels from page...??
17850 if (this.stylesheets === false) {
17852 Roo.get(document.head).select('style').each(function(node) {
17853 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17856 Roo.get(document.head).select('link').each(function(node) {
17857 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17860 } else if (!this.stylesheets.length) {
17862 st = '<style type="text/css">' +
17863 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17869 st += '<style type="text/css">' +
17870 'IMG { cursor: pointer } ' +
17874 return '<html><head>' + st +
17875 //<style type="text/css">' +
17876 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17878 ' </head><body class="roo-htmleditor-body"></body></html>';
17882 onRender : function(ct, position)
17885 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17886 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17889 this.el.dom.style.border = '0 none';
17890 this.el.dom.setAttribute('tabIndex', -1);
17891 this.el.addClass('x-hidden hide');
17895 if(Roo.isIE){ // fix IE 1px bogus margin
17896 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17900 this.frameId = Roo.id();
17904 var iframe = this.owner.wrap.createChild({
17906 cls: 'form-control', // bootstrap..
17908 name: this.frameId,
17909 frameBorder : 'no',
17910 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17915 this.iframe = iframe.dom;
17917 this.assignDocWin();
17919 this.doc.designMode = 'on';
17922 this.doc.write(this.getDocMarkup());
17926 var task = { // must defer to wait for browser to be ready
17928 //console.log("run task?" + this.doc.readyState);
17929 this.assignDocWin();
17930 if(this.doc.body || this.doc.readyState == 'complete'){
17932 this.doc.designMode="on";
17936 Roo.TaskMgr.stop(task);
17937 this.initEditor.defer(10, this);
17944 Roo.TaskMgr.start(task);
17949 onResize : function(w, h)
17951 Roo.log('resize: ' +w + ',' + h );
17952 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17956 if(typeof w == 'number'){
17958 this.iframe.style.width = w + 'px';
17960 if(typeof h == 'number'){
17962 this.iframe.style.height = h + 'px';
17964 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17971 * Toggles the editor between standard and source edit mode.
17972 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17974 toggleSourceEdit : function(sourceEditMode){
17976 this.sourceEditMode = sourceEditMode === true;
17978 if(this.sourceEditMode){
17980 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17983 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17984 //this.iframe.className = '';
17987 //this.setSize(this.owner.wrap.getSize());
17988 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17995 * Protected method that will not generally be called directly. If you need/want
17996 * custom HTML cleanup, this is the method you should override.
17997 * @param {String} html The HTML to be cleaned
17998 * return {String} The cleaned HTML
18000 cleanHtml : function(html){
18001 html = String(html);
18002 if(html.length > 5){
18003 if(Roo.isSafari){ // strip safari nonsense
18004 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18007 if(html == ' '){
18014 * HTML Editor -> Textarea
18015 * Protected method that will not generally be called directly. Syncs the contents
18016 * of the editor iframe with the textarea.
18018 syncValue : function(){
18019 if(this.initialized){
18020 var bd = (this.doc.body || this.doc.documentElement);
18021 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18022 var html = bd.innerHTML;
18024 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18025 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18027 html = '<div style="'+m[0]+'">' + html + '</div>';
18030 html = this.cleanHtml(html);
18031 // fix up the special chars.. normaly like back quotes in word...
18032 // however we do not want to do this with chinese..
18033 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18034 var cc = b.charCodeAt();
18036 (cc >= 0x4E00 && cc < 0xA000 ) ||
18037 (cc >= 0x3400 && cc < 0x4E00 ) ||
18038 (cc >= 0xf900 && cc < 0xfb00 )
18044 if(this.owner.fireEvent('beforesync', this, html) !== false){
18045 this.el.dom.value = html;
18046 this.owner.fireEvent('sync', this, html);
18052 * Protected method that will not generally be called directly. Pushes the value of the textarea
18053 * into the iframe editor.
18055 pushValue : function(){
18056 if(this.initialized){
18057 var v = this.el.dom.value.trim();
18059 // if(v.length < 1){
18063 if(this.owner.fireEvent('beforepush', this, v) !== false){
18064 var d = (this.doc.body || this.doc.documentElement);
18066 this.cleanUpPaste();
18067 this.el.dom.value = d.innerHTML;
18068 this.owner.fireEvent('push', this, v);
18074 deferFocus : function(){
18075 this.focus.defer(10, this);
18079 focus : function(){
18080 if(this.win && !this.sourceEditMode){
18087 assignDocWin: function()
18089 var iframe = this.iframe;
18092 this.doc = iframe.contentWindow.document;
18093 this.win = iframe.contentWindow;
18095 // if (!Roo.get(this.frameId)) {
18098 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18099 // this.win = Roo.get(this.frameId).dom.contentWindow;
18101 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18105 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18106 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18111 initEditor : function(){
18112 //console.log("INIT EDITOR");
18113 this.assignDocWin();
18117 this.doc.designMode="on";
18119 this.doc.write(this.getDocMarkup());
18122 var dbody = (this.doc.body || this.doc.documentElement);
18123 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18124 // this copies styles from the containing element into thsi one..
18125 // not sure why we need all of this..
18126 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18128 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18129 //ss['background-attachment'] = 'fixed'; // w3c
18130 dbody.bgProperties = 'fixed'; // ie
18131 //Roo.DomHelper.applyStyles(dbody, ss);
18132 Roo.EventManager.on(this.doc, {
18133 //'mousedown': this.onEditorEvent,
18134 'mouseup': this.onEditorEvent,
18135 'dblclick': this.onEditorEvent,
18136 'click': this.onEditorEvent,
18137 'keyup': this.onEditorEvent,
18142 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18144 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18145 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18147 this.initialized = true;
18149 this.owner.fireEvent('initialize', this);
18154 onDestroy : function(){
18160 //for (var i =0; i < this.toolbars.length;i++) {
18161 // // fixme - ask toolbars for heights?
18162 // this.toolbars[i].onDestroy();
18165 //this.wrap.dom.innerHTML = '';
18166 //this.wrap.remove();
18171 onFirstFocus : function(){
18173 this.assignDocWin();
18176 this.activated = true;
18179 if(Roo.isGecko){ // prevent silly gecko errors
18181 var s = this.win.getSelection();
18182 if(!s.focusNode || s.focusNode.nodeType != 3){
18183 var r = s.getRangeAt(0);
18184 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18189 this.execCmd('useCSS', true);
18190 this.execCmd('styleWithCSS', false);
18193 this.owner.fireEvent('activate', this);
18197 adjustFont: function(btn){
18198 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18199 //if(Roo.isSafari){ // safari
18202 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18203 if(Roo.isSafari){ // safari
18204 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18205 v = (v < 10) ? 10 : v;
18206 v = (v > 48) ? 48 : v;
18207 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18212 v = Math.max(1, v+adjust);
18214 this.execCmd('FontSize', v );
18217 onEditorEvent : function(e){
18218 this.owner.fireEvent('editorevent', this, e);
18219 // this.updateToolbar();
18220 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18223 insertTag : function(tg)
18225 // could be a bit smarter... -> wrap the current selected tRoo..
18226 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18228 range = this.createRange(this.getSelection());
18229 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18230 wrappingNode.appendChild(range.extractContents());
18231 range.insertNode(wrappingNode);
18238 this.execCmd("formatblock", tg);
18242 insertText : function(txt)
18246 var range = this.createRange();
18247 range.deleteContents();
18248 //alert(Sender.getAttribute('label'));
18250 range.insertNode(this.doc.createTextNode(txt));
18256 * Executes a Midas editor command on the editor document and performs necessary focus and
18257 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18258 * @param {String} cmd The Midas command
18259 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18261 relayCmd : function(cmd, value){
18263 this.execCmd(cmd, value);
18264 this.owner.fireEvent('editorevent', this);
18265 //this.updateToolbar();
18266 this.owner.deferFocus();
18270 * Executes a Midas editor command directly on the editor document.
18271 * For visual commands, you should use {@link #relayCmd} instead.
18272 * <b>This should only be called after the editor is initialized.</b>
18273 * @param {String} cmd The Midas command
18274 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18276 execCmd : function(cmd, value){
18277 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18284 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18286 * @param {String} text | dom node..
18288 insertAtCursor : function(text)
18293 if(!this.activated){
18299 var r = this.doc.selection.createRange();
18310 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18314 // from jquery ui (MIT licenced)
18316 var win = this.win;
18318 if (win.getSelection && win.getSelection().getRangeAt) {
18319 range = win.getSelection().getRangeAt(0);
18320 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18321 range.insertNode(node);
18322 } else if (win.document.selection && win.document.selection.createRange) {
18323 // no firefox support
18324 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18325 win.document.selection.createRange().pasteHTML(txt);
18327 // no firefox support
18328 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18329 this.execCmd('InsertHTML', txt);
18338 mozKeyPress : function(e){
18340 var c = e.getCharCode(), cmd;
18343 c = String.fromCharCode(c).toLowerCase();
18357 this.cleanUpPaste.defer(100, this);
18365 e.preventDefault();
18373 fixKeys : function(){ // load time branching for fastest keydown performance
18375 return function(e){
18376 var k = e.getKey(), r;
18379 r = this.doc.selection.createRange();
18382 r.pasteHTML('    ');
18389 r = this.doc.selection.createRange();
18391 var target = r.parentElement();
18392 if(!target || target.tagName.toLowerCase() != 'li'){
18394 r.pasteHTML('<br />');
18400 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18401 this.cleanUpPaste.defer(100, this);
18407 }else if(Roo.isOpera){
18408 return function(e){
18409 var k = e.getKey();
18413 this.execCmd('InsertHTML','    ');
18416 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18417 this.cleanUpPaste.defer(100, this);
18422 }else if(Roo.isSafari){
18423 return function(e){
18424 var k = e.getKey();
18428 this.execCmd('InsertText','\t');
18432 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18433 this.cleanUpPaste.defer(100, this);
18441 getAllAncestors: function()
18443 var p = this.getSelectedNode();
18446 a.push(p); // push blank onto stack..
18447 p = this.getParentElement();
18451 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18455 a.push(this.doc.body);
18459 lastSelNode : false,
18462 getSelection : function()
18464 this.assignDocWin();
18465 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18468 getSelectedNode: function()
18470 // this may only work on Gecko!!!
18472 // should we cache this!!!!
18477 var range = this.createRange(this.getSelection()).cloneRange();
18480 var parent = range.parentElement();
18482 var testRange = range.duplicate();
18483 testRange.moveToElementText(parent);
18484 if (testRange.inRange(range)) {
18487 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18490 parent = parent.parentElement;
18495 // is ancestor a text element.
18496 var ac = range.commonAncestorContainer;
18497 if (ac.nodeType == 3) {
18498 ac = ac.parentNode;
18501 var ar = ac.childNodes;
18504 var other_nodes = [];
18505 var has_other_nodes = false;
18506 for (var i=0;i<ar.length;i++) {
18507 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18510 // fullly contained node.
18512 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18517 // probably selected..
18518 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18519 other_nodes.push(ar[i]);
18523 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18528 has_other_nodes = true;
18530 if (!nodes.length && other_nodes.length) {
18531 nodes= other_nodes;
18533 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18539 createRange: function(sel)
18541 // this has strange effects when using with
18542 // top toolbar - not sure if it's a great idea.
18543 //this.editor.contentWindow.focus();
18544 if (typeof sel != "undefined") {
18546 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18548 return this.doc.createRange();
18551 return this.doc.createRange();
18554 getParentElement: function()
18557 this.assignDocWin();
18558 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18560 var range = this.createRange(sel);
18563 var p = range.commonAncestorContainer;
18564 while (p.nodeType == 3) { // text node
18575 * Range intersection.. the hard stuff...
18579 * [ -- selected range --- ]
18583 * if end is before start or hits it. fail.
18584 * if start is after end or hits it fail.
18586 * if either hits (but other is outside. - then it's not
18592 // @see http://www.thismuchiknow.co.uk/?p=64.
18593 rangeIntersectsNode : function(range, node)
18595 var nodeRange = node.ownerDocument.createRange();
18597 nodeRange.selectNode(node);
18599 nodeRange.selectNodeContents(node);
18602 var rangeStartRange = range.cloneRange();
18603 rangeStartRange.collapse(true);
18605 var rangeEndRange = range.cloneRange();
18606 rangeEndRange.collapse(false);
18608 var nodeStartRange = nodeRange.cloneRange();
18609 nodeStartRange.collapse(true);
18611 var nodeEndRange = nodeRange.cloneRange();
18612 nodeEndRange.collapse(false);
18614 return rangeStartRange.compareBoundaryPoints(
18615 Range.START_TO_START, nodeEndRange) == -1 &&
18616 rangeEndRange.compareBoundaryPoints(
18617 Range.START_TO_START, nodeStartRange) == 1;
18621 rangeCompareNode : function(range, node)
18623 var nodeRange = node.ownerDocument.createRange();
18625 nodeRange.selectNode(node);
18627 nodeRange.selectNodeContents(node);
18631 range.collapse(true);
18633 nodeRange.collapse(true);
18635 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18636 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18638 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18640 var nodeIsBefore = ss == 1;
18641 var nodeIsAfter = ee == -1;
18643 if (nodeIsBefore && nodeIsAfter)
18645 if (!nodeIsBefore && nodeIsAfter)
18646 return 1; //right trailed.
18648 if (nodeIsBefore && !nodeIsAfter)
18649 return 2; // left trailed.
18654 // private? - in a new class?
18655 cleanUpPaste : function()
18657 // cleans up the whole document..
18658 Roo.log('cleanuppaste');
18660 this.cleanUpChildren(this.doc.body);
18661 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18662 if (clean != this.doc.body.innerHTML) {
18663 this.doc.body.innerHTML = clean;
18668 cleanWordChars : function(input) {// change the chars to hex code
18669 var he = Roo.HtmlEditorCore;
18671 var output = input;
18672 Roo.each(he.swapCodes, function(sw) {
18673 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18675 output = output.replace(swapper, sw[1]);
18682 cleanUpChildren : function (n)
18684 if (!n.childNodes.length) {
18687 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18688 this.cleanUpChild(n.childNodes[i]);
18695 cleanUpChild : function (node)
18698 //console.log(node);
18699 if (node.nodeName == "#text") {
18700 // clean up silly Windows -- stuff?
18703 if (node.nodeName == "#comment") {
18704 node.parentNode.removeChild(node);
18705 // clean up silly Windows -- stuff?
18708 var lcname = node.tagName.toLowerCase();
18709 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18710 // whitelist of tags..
18712 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18714 node.parentNode.removeChild(node);
18719 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18721 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18722 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18724 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18725 // remove_keep_children = true;
18728 if (remove_keep_children) {
18729 this.cleanUpChildren(node);
18730 // inserts everything just before this node...
18731 while (node.childNodes.length) {
18732 var cn = node.childNodes[0];
18733 node.removeChild(cn);
18734 node.parentNode.insertBefore(cn, node);
18736 node.parentNode.removeChild(node);
18740 if (!node.attributes || !node.attributes.length) {
18741 this.cleanUpChildren(node);
18745 function cleanAttr(n,v)
18748 if (v.match(/^\./) || v.match(/^\//)) {
18751 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18754 if (v.match(/^#/)) {
18757 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18758 node.removeAttribute(n);
18762 var cwhite = this.cwhite;
18763 var cblack = this.cblack;
18765 function cleanStyle(n,v)
18767 if (v.match(/expression/)) { //XSS?? should we even bother..
18768 node.removeAttribute(n);
18772 var parts = v.split(/;/);
18775 Roo.each(parts, function(p) {
18776 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18780 var l = p.split(':').shift().replace(/\s+/g,'');
18781 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18783 if ( cwhite.length && cblack.indexOf(l) > -1) {
18784 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18785 //node.removeAttribute(n);
18789 // only allow 'c whitelisted system attributes'
18790 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18791 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18792 //node.removeAttribute(n);
18802 if (clean.length) {
18803 node.setAttribute(n, clean.join(';'));
18805 node.removeAttribute(n);
18811 for (var i = node.attributes.length-1; i > -1 ; i--) {
18812 var a = node.attributes[i];
18815 if (a.name.toLowerCase().substr(0,2)=='on') {
18816 node.removeAttribute(a.name);
18819 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18820 node.removeAttribute(a.name);
18823 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18824 cleanAttr(a.name,a.value); // fixme..
18827 if (a.name == 'style') {
18828 cleanStyle(a.name,a.value);
18831 /// clean up MS crap..
18832 // tecnically this should be a list of valid class'es..
18835 if (a.name == 'class') {
18836 if (a.value.match(/^Mso/)) {
18837 node.className = '';
18840 if (a.value.match(/body/)) {
18841 node.className = '';
18852 this.cleanUpChildren(node);
18857 * Clean up MS wordisms...
18859 cleanWord : function(node)
18862 var cleanWordChildren = function()
18864 if (!node.childNodes.length) {
18867 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18868 _t.cleanWord(node.childNodes[i]);
18874 this.cleanWord(this.doc.body);
18877 if (node.nodeName == "#text") {
18878 // clean up silly Windows -- stuff?
18881 if (node.nodeName == "#comment") {
18882 node.parentNode.removeChild(node);
18883 // clean up silly Windows -- stuff?
18887 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18888 node.parentNode.removeChild(node);
18892 // remove - but keep children..
18893 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18894 while (node.childNodes.length) {
18895 var cn = node.childNodes[0];
18896 node.removeChild(cn);
18897 node.parentNode.insertBefore(cn, node);
18899 node.parentNode.removeChild(node);
18900 cleanWordChildren();
18904 if (node.className.length) {
18906 var cn = node.className.split(/\W+/);
18908 Roo.each(cn, function(cls) {
18909 if (cls.match(/Mso[a-zA-Z]+/)) {
18914 node.className = cna.length ? cna.join(' ') : '';
18916 node.removeAttribute("class");
18920 if (node.hasAttribute("lang")) {
18921 node.removeAttribute("lang");
18924 if (node.hasAttribute("style")) {
18926 var styles = node.getAttribute("style").split(";");
18928 Roo.each(styles, function(s) {
18929 if (!s.match(/:/)) {
18932 var kv = s.split(":");
18933 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18936 // what ever is left... we allow.
18939 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18940 if (!nstyle.length) {
18941 node.removeAttribute('style');
18945 cleanWordChildren();
18949 domToHTML : function(currentElement, depth, nopadtext) {
18951 depth = depth || 0;
18952 nopadtext = nopadtext || false;
18954 if (!currentElement) {
18955 return this.domToHTML(this.doc.body);
18958 //Roo.log(currentElement);
18960 var allText = false;
18961 var nodeName = currentElement.nodeName;
18962 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18964 if (nodeName == '#text') {
18966 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18971 if (nodeName != 'BODY') {
18974 // Prints the node tagName, such as <A>, <IMG>, etc
18977 for(i = 0; i < currentElement.attributes.length;i++) {
18979 var aname = currentElement.attributes.item(i).name;
18980 if (!currentElement.attributes.item(i).value.length) {
18983 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18986 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18995 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18998 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19003 // Traverse the tree
19005 var currentElementChild = currentElement.childNodes.item(i);
19006 var allText = true;
19007 var innerHTML = '';
19009 while (currentElementChild) {
19010 // Formatting code (indent the tree so it looks nice on the screen)
19011 var nopad = nopadtext;
19012 if (lastnode == 'SPAN') {
19016 if (currentElementChild.nodeName == '#text') {
19017 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19018 toadd = nopadtext ? toadd : toadd.trim();
19019 if (!nopad && toadd.length > 80) {
19020 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19022 innerHTML += toadd;
19025 currentElementChild = currentElement.childNodes.item(i);
19031 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19033 // Recursively traverse the tree structure of the child node
19034 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19035 lastnode = currentElementChild.nodeName;
19037 currentElementChild=currentElement.childNodes.item(i);
19043 // The remaining code is mostly for formatting the tree
19044 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19049 ret+= "</"+tagName+">";
19055 applyBlacklists : function()
19057 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19058 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19062 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19063 if (b.indexOf(tag) > -1) {
19066 this.white.push(tag);
19070 Roo.each(w, function(tag) {
19071 if (b.indexOf(tag) > -1) {
19074 if (this.white.indexOf(tag) > -1) {
19077 this.white.push(tag);
19082 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19083 if (w.indexOf(tag) > -1) {
19086 this.black.push(tag);
19090 Roo.each(b, function(tag) {
19091 if (w.indexOf(tag) > -1) {
19094 if (this.black.indexOf(tag) > -1) {
19097 this.black.push(tag);
19102 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19103 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19107 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19108 if (b.indexOf(tag) > -1) {
19111 this.cwhite.push(tag);
19115 Roo.each(w, function(tag) {
19116 if (b.indexOf(tag) > -1) {
19119 if (this.cwhite.indexOf(tag) > -1) {
19122 this.cwhite.push(tag);
19127 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19128 if (w.indexOf(tag) > -1) {
19131 this.cblack.push(tag);
19135 Roo.each(b, function(tag) {
19136 if (w.indexOf(tag) > -1) {
19139 if (this.cblack.indexOf(tag) > -1) {
19142 this.cblack.push(tag);
19147 setStylesheets : function(stylesheets)
19149 if(typeof(stylesheets) == 'string'){
19150 Roo.get(this.iframe.contentDocument.head).createChild({
19152 rel : 'stylesheet',
19161 Roo.each(stylesheets, function(s) {
19166 Roo.get(_this.iframe.contentDocument.head).createChild({
19168 rel : 'stylesheet',
19177 removeStylesheets : function()
19181 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19186 // hide stuff that is not compatible
19200 * @event specialkey
19204 * @cfg {String} fieldClass @hide
19207 * @cfg {String} focusClass @hide
19210 * @cfg {String} autoCreate @hide
19213 * @cfg {String} inputType @hide
19216 * @cfg {String} invalidClass @hide
19219 * @cfg {String} invalidText @hide
19222 * @cfg {String} msgFx @hide
19225 * @cfg {String} validateOnBlur @hide
19229 Roo.HtmlEditorCore.white = [
19230 'area', 'br', 'img', 'input', 'hr', 'wbr',
19232 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19233 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19234 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19235 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19236 'table', 'ul', 'xmp',
19238 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19241 'dir', 'menu', 'ol', 'ul', 'dl',
19247 Roo.HtmlEditorCore.black = [
19248 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19250 'base', 'basefont', 'bgsound', 'blink', 'body',
19251 'frame', 'frameset', 'head', 'html', 'ilayer',
19252 'iframe', 'layer', 'link', 'meta', 'object',
19253 'script', 'style' ,'title', 'xml' // clean later..
19255 Roo.HtmlEditorCore.clean = [
19256 'script', 'style', 'title', 'xml'
19258 Roo.HtmlEditorCore.remove = [
19263 Roo.HtmlEditorCore.ablack = [
19267 Roo.HtmlEditorCore.aclean = [
19268 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19272 Roo.HtmlEditorCore.pwhite= [
19273 'http', 'https', 'mailto'
19276 // white listed style attributes.
19277 Roo.HtmlEditorCore.cwhite= [
19278 // 'text-align', /// default is to allow most things..
19284 // black listed style attributes.
19285 Roo.HtmlEditorCore.cblack= [
19286 // 'font-size' -- this can be set by the project
19290 Roo.HtmlEditorCore.swapCodes =[
19309 * @class Roo.bootstrap.HtmlEditor
19310 * @extends Roo.bootstrap.TextArea
19311 * Bootstrap HtmlEditor class
19314 * Create a new HtmlEditor
19315 * @param {Object} config The config object
19318 Roo.bootstrap.HtmlEditor = function(config){
19319 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19320 if (!this.toolbars) {
19321 this.toolbars = [];
19323 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19326 * @event initialize
19327 * Fires when the editor is fully initialized (including the iframe)
19328 * @param {HtmlEditor} this
19333 * Fires when the editor is first receives the focus. Any insertion must wait
19334 * until after this event.
19335 * @param {HtmlEditor} this
19339 * @event beforesync
19340 * Fires before the textarea is updated with content from the editor iframe. Return false
19341 * to cancel the sync.
19342 * @param {HtmlEditor} this
19343 * @param {String} html
19347 * @event beforepush
19348 * Fires before the iframe editor is updated with content from the textarea. Return false
19349 * to cancel the push.
19350 * @param {HtmlEditor} this
19351 * @param {String} html
19356 * Fires when the textarea is updated with content from the editor iframe.
19357 * @param {HtmlEditor} this
19358 * @param {String} html
19363 * Fires when the iframe editor is updated with content from the textarea.
19364 * @param {HtmlEditor} this
19365 * @param {String} html
19369 * @event editmodechange
19370 * Fires when the editor switches edit modes
19371 * @param {HtmlEditor} this
19372 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19374 editmodechange: true,
19376 * @event editorevent
19377 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19378 * @param {HtmlEditor} this
19382 * @event firstfocus
19383 * Fires when on first focus - needed by toolbars..
19384 * @param {HtmlEditor} this
19389 * Auto save the htmlEditor value as a file into Events
19390 * @param {HtmlEditor} this
19394 * @event savedpreview
19395 * preview the saved version of htmlEditor
19396 * @param {HtmlEditor} this
19403 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19407 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19412 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19417 * @cfg {Number} height (in pixels)
19421 * @cfg {Number} width (in pixels)
19426 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19429 stylesheets: false,
19434 // private properties
19435 validationEvent : false,
19437 initialized : false,
19440 onFocus : Roo.emptyFn,
19442 hideMode:'offsets',
19445 tbContainer : false,
19447 toolbarContainer :function() {
19448 return this.wrap.select('.x-html-editor-tb',true).first();
19452 * Protected method that will not generally be called directly. It
19453 * is called when the editor creates its toolbar. Override this method if you need to
19454 * add custom toolbar buttons.
19455 * @param {HtmlEditor} editor
19457 createToolbar : function(){
19459 Roo.log("create toolbars");
19461 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19462 this.toolbars[0].render(this.toolbarContainer());
19466 // if (!editor.toolbars || !editor.toolbars.length) {
19467 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19470 // for (var i =0 ; i < editor.toolbars.length;i++) {
19471 // editor.toolbars[i] = Roo.factory(
19472 // typeof(editor.toolbars[i]) == 'string' ?
19473 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19474 // Roo.bootstrap.HtmlEditor);
19475 // editor.toolbars[i].init(editor);
19481 onRender : function(ct, position)
19483 // Roo.log("Call onRender: " + this.xtype);
19485 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19487 this.wrap = this.inputEl().wrap({
19488 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19491 this.editorcore.onRender(ct, position);
19493 if (this.resizable) {
19494 this.resizeEl = new Roo.Resizable(this.wrap, {
19498 minHeight : this.height,
19499 height: this.height,
19500 handles : this.resizable,
19503 resize : function(r, w, h) {
19504 _t.onResize(w,h); // -something
19510 this.createToolbar(this);
19513 if(!this.width && this.resizable){
19514 this.setSize(this.wrap.getSize());
19516 if (this.resizeEl) {
19517 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19518 // should trigger onReize..
19524 onResize : function(w, h)
19526 Roo.log('resize: ' +w + ',' + h );
19527 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19531 if(this.inputEl() ){
19532 if(typeof w == 'number'){
19533 var aw = w - this.wrap.getFrameWidth('lr');
19534 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19537 if(typeof h == 'number'){
19538 var tbh = -11; // fixme it needs to tool bar size!
19539 for (var i =0; i < this.toolbars.length;i++) {
19540 // fixme - ask toolbars for heights?
19541 tbh += this.toolbars[i].el.getHeight();
19542 //if (this.toolbars[i].footer) {
19543 // tbh += this.toolbars[i].footer.el.getHeight();
19551 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19552 ah -= 5; // knock a few pixes off for look..
19553 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19557 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19558 this.editorcore.onResize(ew,eh);
19563 * Toggles the editor between standard and source edit mode.
19564 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19566 toggleSourceEdit : function(sourceEditMode)
19568 this.editorcore.toggleSourceEdit(sourceEditMode);
19570 if(this.editorcore.sourceEditMode){
19571 Roo.log('editor - showing textarea');
19574 // Roo.log(this.syncValue());
19576 this.inputEl().removeClass(['hide', 'x-hidden']);
19577 this.inputEl().dom.removeAttribute('tabIndex');
19578 this.inputEl().focus();
19580 Roo.log('editor - hiding textarea');
19582 // Roo.log(this.pushValue());
19585 this.inputEl().addClass(['hide', 'x-hidden']);
19586 this.inputEl().dom.setAttribute('tabIndex', -1);
19587 //this.deferFocus();
19590 if(this.resizable){
19591 this.setSize(this.wrap.getSize());
19594 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19597 // private (for BoxComponent)
19598 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19600 // private (for BoxComponent)
19601 getResizeEl : function(){
19605 // private (for BoxComponent)
19606 getPositionEl : function(){
19611 initEvents : function(){
19612 this.originalValue = this.getValue();
19616 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19619 // markInvalid : Roo.emptyFn,
19621 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19624 // clearInvalid : Roo.emptyFn,
19626 setValue : function(v){
19627 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19628 this.editorcore.pushValue();
19633 deferFocus : function(){
19634 this.focus.defer(10, this);
19638 focus : function(){
19639 this.editorcore.focus();
19645 onDestroy : function(){
19651 for (var i =0; i < this.toolbars.length;i++) {
19652 // fixme - ask toolbars for heights?
19653 this.toolbars[i].onDestroy();
19656 this.wrap.dom.innerHTML = '';
19657 this.wrap.remove();
19662 onFirstFocus : function(){
19663 //Roo.log("onFirstFocus");
19664 this.editorcore.onFirstFocus();
19665 for (var i =0; i < this.toolbars.length;i++) {
19666 this.toolbars[i].onFirstFocus();
19672 syncValue : function()
19674 this.editorcore.syncValue();
19677 pushValue : function()
19679 this.editorcore.pushValue();
19683 // hide stuff that is not compatible
19697 * @event specialkey
19701 * @cfg {String} fieldClass @hide
19704 * @cfg {String} focusClass @hide
19707 * @cfg {String} autoCreate @hide
19710 * @cfg {String} inputType @hide
19713 * @cfg {String} invalidClass @hide
19716 * @cfg {String} invalidText @hide
19719 * @cfg {String} msgFx @hide
19722 * @cfg {String} validateOnBlur @hide
19731 Roo.namespace('Roo.bootstrap.htmleditor');
19733 * @class Roo.bootstrap.HtmlEditorToolbar1
19738 new Roo.bootstrap.HtmlEditor({
19741 new Roo.bootstrap.HtmlEditorToolbar1({
19742 disable : { fonts: 1 , format: 1, ..., ... , ...],
19748 * @cfg {Object} disable List of elements to disable..
19749 * @cfg {Array} btns List of additional buttons.
19753 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19756 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19759 Roo.apply(this, config);
19761 // default disabled, based on 'good practice'..
19762 this.disable = this.disable || {};
19763 Roo.applyIf(this.disable, {
19766 specialElements : true
19768 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19770 this.editor = config.editor;
19771 this.editorcore = config.editor.editorcore;
19773 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19775 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19776 // dont call parent... till later.
19778 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19783 editorcore : false,
19788 "h1","h2","h3","h4","h5","h6",
19790 "abbr", "acronym", "address", "cite", "samp", "var",
19794 onRender : function(ct, position)
19796 // Roo.log("Call onRender: " + this.xtype);
19798 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19800 this.el.dom.style.marginBottom = '0';
19802 var editorcore = this.editorcore;
19803 var editor= this.editor;
19806 var btn = function(id,cmd , toggle, handler){
19808 var event = toggle ? 'toggle' : 'click';
19813 xns: Roo.bootstrap,
19816 enableToggle:toggle !== false,
19818 pressed : toggle ? false : null,
19821 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19822 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19831 xns: Roo.bootstrap,
19832 glyphicon : 'font',
19836 xns: Roo.bootstrap,
19840 Roo.each(this.formats, function(f) {
19841 style.menu.items.push({
19843 xns: Roo.bootstrap,
19844 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19849 editorcore.insertTag(this.tagname);
19856 children.push(style);
19859 btn('bold',false,true);
19860 btn('italic',false,true);
19861 btn('align-left', 'justifyleft',true);
19862 btn('align-center', 'justifycenter',true);
19863 btn('align-right' , 'justifyright',true);
19864 btn('link', false, false, function(btn) {
19865 //Roo.log("create link?");
19866 var url = prompt(this.createLinkText, this.defaultLinkValue);
19867 if(url && url != 'http:/'+'/'){
19868 this.editorcore.relayCmd('createlink', url);
19871 btn('list','insertunorderedlist',true);
19872 btn('pencil', false,true, function(btn){
19875 this.toggleSourceEdit(btn.pressed);
19881 xns: Roo.bootstrap,
19886 xns: Roo.bootstrap,
19891 cog.menu.items.push({
19893 xns: Roo.bootstrap,
19894 html : Clean styles,
19899 editorcore.insertTag(this.tagname);
19908 this.xtype = 'NavSimplebar';
19910 for(var i=0;i< children.length;i++) {
19912 this.buttons.add(this.addxtypeChild(children[i]));
19916 editor.on('editorevent', this.updateToolbar, this);
19918 onBtnClick : function(id)
19920 this.editorcore.relayCmd(id);
19921 this.editorcore.focus();
19925 * Protected method that will not generally be called directly. It triggers
19926 * a toolbar update by reading the markup state of the current selection in the editor.
19928 updateToolbar: function(){
19930 if(!this.editorcore.activated){
19931 this.editor.onFirstFocus(); // is this neeed?
19935 var btns = this.buttons;
19936 var doc = this.editorcore.doc;
19937 btns.get('bold').setActive(doc.queryCommandState('bold'));
19938 btns.get('italic').setActive(doc.queryCommandState('italic'));
19939 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19941 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19942 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19943 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19945 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19946 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19949 var ans = this.editorcore.getAllAncestors();
19950 if (this.formatCombo) {
19953 var store = this.formatCombo.store;
19954 this.formatCombo.setValue("");
19955 for (var i =0; i < ans.length;i++) {
19956 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19958 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19966 // hides menus... - so this cant be on a menu...
19967 Roo.bootstrap.MenuMgr.hideAll();
19969 Roo.bootstrap.MenuMgr.hideAll();
19970 //this.editorsyncValue();
19972 onFirstFocus: function() {
19973 this.buttons.each(function(item){
19977 toggleSourceEdit : function(sourceEditMode){
19980 if(sourceEditMode){
19981 Roo.log("disabling buttons");
19982 this.buttons.each( function(item){
19983 if(item.cmd != 'pencil'){
19989 Roo.log("enabling buttons");
19990 if(this.editorcore.initialized){
19991 this.buttons.each( function(item){
19997 Roo.log("calling toggole on editor");
19998 // tell the editor that it's been pressed..
19999 this.editor.toggleSourceEdit(sourceEditMode);
20009 * @class Roo.bootstrap.Table.AbstractSelectionModel
20010 * @extends Roo.util.Observable
20011 * Abstract base class for grid SelectionModels. It provides the interface that should be
20012 * implemented by descendant classes. This class should not be directly instantiated.
20015 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20016 this.locked = false;
20017 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20021 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20022 /** @ignore Called by the grid automatically. Do not call directly. */
20023 init : function(grid){
20029 * Locks the selections.
20032 this.locked = true;
20036 * Unlocks the selections.
20038 unlock : function(){
20039 this.locked = false;
20043 * Returns true if the selections are locked.
20044 * @return {Boolean}
20046 isLocked : function(){
20047 return this.locked;
20051 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20052 * @class Roo.bootstrap.Table.RowSelectionModel
20053 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20054 * It supports multiple selections and keyboard selection/navigation.
20056 * @param {Object} config
20059 Roo.bootstrap.Table.RowSelectionModel = function(config){
20060 Roo.apply(this, config);
20061 this.selections = new Roo.util.MixedCollection(false, function(o){
20066 this.lastActive = false;
20070 * @event selectionchange
20071 * Fires when the selection changes
20072 * @param {SelectionModel} this
20074 "selectionchange" : true,
20076 * @event afterselectionchange
20077 * Fires after the selection changes (eg. by key press or clicking)
20078 * @param {SelectionModel} this
20080 "afterselectionchange" : true,
20082 * @event beforerowselect
20083 * Fires when a row is selected being selected, return false to cancel.
20084 * @param {SelectionModel} this
20085 * @param {Number} rowIndex The selected index
20086 * @param {Boolean} keepExisting False if other selections will be cleared
20088 "beforerowselect" : true,
20091 * Fires when a row is selected.
20092 * @param {SelectionModel} this
20093 * @param {Number} rowIndex The selected index
20094 * @param {Roo.data.Record} r The record
20096 "rowselect" : true,
20098 * @event rowdeselect
20099 * Fires when a row is deselected.
20100 * @param {SelectionModel} this
20101 * @param {Number} rowIndex The selected index
20103 "rowdeselect" : true
20105 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20106 this.locked = false;
20109 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20111 * @cfg {Boolean} singleSelect
20112 * True to allow selection of only one row at a time (defaults to false)
20114 singleSelect : false,
20117 initEvents : function(){
20119 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20120 this.grid.on("mousedown", this.handleMouseDown, this);
20121 }else{ // allow click to work like normal
20122 this.grid.on("rowclick", this.handleDragableRowClick, this);
20125 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20126 "up" : function(e){
20128 this.selectPrevious(e.shiftKey);
20129 }else if(this.last !== false && this.lastActive !== false){
20130 var last = this.last;
20131 this.selectRange(this.last, this.lastActive-1);
20132 this.grid.getView().focusRow(this.lastActive);
20133 if(last !== false){
20137 this.selectFirstRow();
20139 this.fireEvent("afterselectionchange", this);
20141 "down" : function(e){
20143 this.selectNext(e.shiftKey);
20144 }else if(this.last !== false && this.lastActive !== false){
20145 var last = this.last;
20146 this.selectRange(this.last, this.lastActive+1);
20147 this.grid.getView().focusRow(this.lastActive);
20148 if(last !== false){
20152 this.selectFirstRow();
20154 this.fireEvent("afterselectionchange", this);
20159 var view = this.grid.view;
20160 view.on("refresh", this.onRefresh, this);
20161 view.on("rowupdated", this.onRowUpdated, this);
20162 view.on("rowremoved", this.onRemove, this);
20166 onRefresh : function(){
20167 var ds = this.grid.dataSource, i, v = this.grid.view;
20168 var s = this.selections;
20169 s.each(function(r){
20170 if((i = ds.indexOfId(r.id)) != -1){
20179 onRemove : function(v, index, r){
20180 this.selections.remove(r);
20184 onRowUpdated : function(v, index, r){
20185 if(this.isSelected(r)){
20186 v.onRowSelect(index);
20192 * @param {Array} records The records to select
20193 * @param {Boolean} keepExisting (optional) True to keep existing selections
20195 selectRecords : function(records, keepExisting){
20197 this.clearSelections();
20199 var ds = this.grid.dataSource;
20200 for(var i = 0, len = records.length; i < len; i++){
20201 this.selectRow(ds.indexOf(records[i]), true);
20206 * Gets the number of selected rows.
20209 getCount : function(){
20210 return this.selections.length;
20214 * Selects the first row in the grid.
20216 selectFirstRow : function(){
20221 * Select the last row.
20222 * @param {Boolean} keepExisting (optional) True to keep existing selections
20224 selectLastRow : function(keepExisting){
20225 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20229 * Selects the row immediately following the last selected row.
20230 * @param {Boolean} keepExisting (optional) True to keep existing selections
20232 selectNext : function(keepExisting){
20233 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20234 this.selectRow(this.last+1, keepExisting);
20235 this.grid.getView().focusRow(this.last);
20240 * Selects the row that precedes the last selected row.
20241 * @param {Boolean} keepExisting (optional) True to keep existing selections
20243 selectPrevious : function(keepExisting){
20245 this.selectRow(this.last-1, keepExisting);
20246 this.grid.getView().focusRow(this.last);
20251 * Returns the selected records
20252 * @return {Array} Array of selected records
20254 getSelections : function(){
20255 return [].concat(this.selections.items);
20259 * Returns the first selected record.
20262 getSelected : function(){
20263 return this.selections.itemAt(0);
20268 * Clears all selections.
20270 clearSelections : function(fast){
20271 if(this.locked) return;
20273 var ds = this.grid.dataSource;
20274 var s = this.selections;
20275 s.each(function(r){
20276 this.deselectRow(ds.indexOfId(r.id));
20280 this.selections.clear();
20287 * Selects all rows.
20289 selectAll : function(){
20290 if(this.locked) return;
20291 this.selections.clear();
20292 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20293 this.selectRow(i, true);
20298 * Returns True if there is a selection.
20299 * @return {Boolean}
20301 hasSelection : function(){
20302 return this.selections.length > 0;
20306 * Returns True if the specified row is selected.
20307 * @param {Number/Record} record The record or index of the record to check
20308 * @return {Boolean}
20310 isSelected : function(index){
20311 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20312 return (r && this.selections.key(r.id) ? true : false);
20316 * Returns True if the specified record id is selected.
20317 * @param {String} id The id of record to check
20318 * @return {Boolean}
20320 isIdSelected : function(id){
20321 return (this.selections.key(id) ? true : false);
20325 handleMouseDown : function(e, t){
20326 var view = this.grid.getView(), rowIndex;
20327 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20330 if(e.shiftKey && this.last !== false){
20331 var last = this.last;
20332 this.selectRange(last, rowIndex, e.ctrlKey);
20333 this.last = last; // reset the last
20334 view.focusRow(rowIndex);
20336 var isSelected = this.isSelected(rowIndex);
20337 if(e.button !== 0 && isSelected){
20338 view.focusRow(rowIndex);
20339 }else if(e.ctrlKey && isSelected){
20340 this.deselectRow(rowIndex);
20341 }else if(!isSelected){
20342 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20343 view.focusRow(rowIndex);
20346 this.fireEvent("afterselectionchange", this);
20349 handleDragableRowClick : function(grid, rowIndex, e)
20351 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20352 this.selectRow(rowIndex, false);
20353 grid.view.focusRow(rowIndex);
20354 this.fireEvent("afterselectionchange", this);
20359 * Selects multiple rows.
20360 * @param {Array} rows Array of the indexes of the row to select
20361 * @param {Boolean} keepExisting (optional) True to keep existing selections
20363 selectRows : function(rows, keepExisting){
20365 this.clearSelections();
20367 for(var i = 0, len = rows.length; i < len; i++){
20368 this.selectRow(rows[i], true);
20373 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20374 * @param {Number} startRow The index of the first row in the range
20375 * @param {Number} endRow The index of the last row in the range
20376 * @param {Boolean} keepExisting (optional) True to retain existing selections
20378 selectRange : function(startRow, endRow, keepExisting){
20379 if(this.locked) return;
20381 this.clearSelections();
20383 if(startRow <= endRow){
20384 for(var i = startRow; i <= endRow; i++){
20385 this.selectRow(i, true);
20388 for(var i = startRow; i >= endRow; i--){
20389 this.selectRow(i, true);
20395 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20396 * @param {Number} startRow The index of the first row in the range
20397 * @param {Number} endRow The index of the last row in the range
20399 deselectRange : function(startRow, endRow, preventViewNotify){
20400 if(this.locked) return;
20401 for(var i = startRow; i <= endRow; i++){
20402 this.deselectRow(i, preventViewNotify);
20408 * @param {Number} row The index of the row to select
20409 * @param {Boolean} keepExisting (optional) True to keep existing selections
20411 selectRow : function(index, keepExisting, preventViewNotify){
20412 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20413 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20414 if(!keepExisting || this.singleSelect){
20415 this.clearSelections();
20417 var r = this.grid.dataSource.getAt(index);
20418 this.selections.add(r);
20419 this.last = this.lastActive = index;
20420 if(!preventViewNotify){
20421 this.grid.getView().onRowSelect(index);
20423 this.fireEvent("rowselect", this, index, r);
20424 this.fireEvent("selectionchange", this);
20430 * @param {Number} row The index of the row to deselect
20432 deselectRow : function(index, preventViewNotify){
20433 if(this.locked) return;
20434 if(this.last == index){
20437 if(this.lastActive == index){
20438 this.lastActive = false;
20440 var r = this.grid.dataSource.getAt(index);
20441 this.selections.remove(r);
20442 if(!preventViewNotify){
20443 this.grid.getView().onRowDeselect(index);
20445 this.fireEvent("rowdeselect", this, index);
20446 this.fireEvent("selectionchange", this);
20450 restoreLast : function(){
20452 this.last = this._last;
20457 acceptsNav : function(row, col, cm){
20458 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20462 onEditorKey : function(field, e){
20463 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20468 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20470 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20472 }else if(k == e.ENTER && !e.ctrlKey){
20476 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20478 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20480 }else if(k == e.ESC){
20484 g.startEditing(newCell[0], newCell[1]);
20489 * Ext JS Library 1.1.1
20490 * Copyright(c) 2006-2007, Ext JS, LLC.
20492 * Originally Released Under LGPL - original licence link has changed is not relivant.
20495 * <script type="text/javascript">
20499 * @class Roo.bootstrap.PagingToolbar
20501 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20503 * Create a new PagingToolbar
20504 * @param {Object} config The config object
20506 Roo.bootstrap.PagingToolbar = function(config)
20508 // old args format still supported... - xtype is prefered..
20509 // created from xtype...
20510 var ds = config.dataSource;
20511 this.toolbarItems = [];
20512 if (config.items) {
20513 this.toolbarItems = config.items;
20514 // config.items = [];
20517 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20524 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20528 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20530 * @cfg {Roo.data.Store} dataSource
20531 * The underlying data store providing the paged data
20534 * @cfg {String/HTMLElement/Element} container
20535 * container The id or element that will contain the toolbar
20538 * @cfg {Boolean} displayInfo
20539 * True to display the displayMsg (defaults to false)
20542 * @cfg {Number} pageSize
20543 * The number of records to display per page (defaults to 20)
20547 * @cfg {String} displayMsg
20548 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20550 displayMsg : 'Displaying {0} - {1} of {2}',
20552 * @cfg {String} emptyMsg
20553 * The message to display when no records are found (defaults to "No data to display")
20555 emptyMsg : 'No data to display',
20557 * Customizable piece of the default paging text (defaults to "Page")
20560 beforePageText : "Page",
20562 * Customizable piece of the default paging text (defaults to "of %0")
20565 afterPageText : "of {0}",
20567 * Customizable piece of the default paging text (defaults to "First Page")
20570 firstText : "First Page",
20572 * Customizable piece of the default paging text (defaults to "Previous Page")
20575 prevText : "Previous Page",
20577 * Customizable piece of the default paging text (defaults to "Next Page")
20580 nextText : "Next Page",
20582 * Customizable piece of the default paging text (defaults to "Last Page")
20585 lastText : "Last Page",
20587 * Customizable piece of the default paging text (defaults to "Refresh")
20590 refreshText : "Refresh",
20594 onRender : function(ct, position)
20596 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20597 this.navgroup.parentId = this.id;
20598 this.navgroup.onRender(this.el, null);
20599 // add the buttons to the navgroup
20601 if(this.displayInfo){
20602 Roo.log(this.el.select('ul.navbar-nav',true).first());
20603 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20604 this.displayEl = this.el.select('.x-paging-info', true).first();
20605 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20606 // this.displayEl = navel.el.select('span',true).first();
20612 Roo.each(_this.buttons, function(e){
20613 Roo.factory(e).onRender(_this.el, null);
20617 Roo.each(_this.toolbarItems, function(e) {
20618 _this.navgroup.addItem(e);
20622 this.first = this.navgroup.addItem({
20623 tooltip: this.firstText,
20625 icon : 'fa fa-backward',
20627 preventDefault: true,
20628 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20631 this.prev = this.navgroup.addItem({
20632 tooltip: this.prevText,
20634 icon : 'fa fa-step-backward',
20636 preventDefault: true,
20637 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20639 //this.addSeparator();
20642 var field = this.navgroup.addItem( {
20644 cls : 'x-paging-position',
20646 html : this.beforePageText +
20647 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20648 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20651 this.field = field.el.select('input', true).first();
20652 this.field.on("keydown", this.onPagingKeydown, this);
20653 this.field.on("focus", function(){this.dom.select();});
20656 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20657 //this.field.setHeight(18);
20658 //this.addSeparator();
20659 this.next = this.navgroup.addItem({
20660 tooltip: this.nextText,
20662 html : ' <i class="fa fa-step-forward">',
20664 preventDefault: true,
20665 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20667 this.last = this.navgroup.addItem({
20668 tooltip: this.lastText,
20669 icon : 'fa fa-forward',
20672 preventDefault: true,
20673 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20675 //this.addSeparator();
20676 this.loading = this.navgroup.addItem({
20677 tooltip: this.refreshText,
20678 icon: 'fa fa-refresh',
20679 preventDefault: true,
20680 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20686 updateInfo : function(){
20687 if(this.displayEl){
20688 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20689 var msg = count == 0 ?
20693 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20695 this.displayEl.update(msg);
20700 onLoad : function(ds, r, o){
20701 this.cursor = o.params ? o.params.start : 0;
20702 var d = this.getPageData(),
20706 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20707 this.field.dom.value = ap;
20708 this.first.setDisabled(ap == 1);
20709 this.prev.setDisabled(ap == 1);
20710 this.next.setDisabled(ap == ps);
20711 this.last.setDisabled(ap == ps);
20712 this.loading.enable();
20717 getPageData : function(){
20718 var total = this.ds.getTotalCount();
20721 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20722 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20727 onLoadError : function(){
20728 this.loading.enable();
20732 onPagingKeydown : function(e){
20733 var k = e.getKey();
20734 var d = this.getPageData();
20736 var v = this.field.dom.value, pageNum;
20737 if(!v || isNaN(pageNum = parseInt(v, 10))){
20738 this.field.dom.value = d.activePage;
20741 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20742 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20745 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))
20747 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20748 this.field.dom.value = pageNum;
20749 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20752 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20754 var v = this.field.dom.value, pageNum;
20755 var increment = (e.shiftKey) ? 10 : 1;
20756 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20758 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20759 this.field.dom.value = d.activePage;
20762 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20764 this.field.dom.value = parseInt(v, 10) + increment;
20765 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20766 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20773 beforeLoad : function(){
20775 this.loading.disable();
20780 onClick : function(which){
20789 ds.load({params:{start: 0, limit: this.pageSize}});
20792 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20795 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20798 var total = ds.getTotalCount();
20799 var extra = total % this.pageSize;
20800 var lastStart = extra ? (total - extra) : total-this.pageSize;
20801 ds.load({params:{start: lastStart, limit: this.pageSize}});
20804 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20810 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20811 * @param {Roo.data.Store} store The data store to unbind
20813 unbind : function(ds){
20814 ds.un("beforeload", this.beforeLoad, this);
20815 ds.un("load", this.onLoad, this);
20816 ds.un("loadexception", this.onLoadError, this);
20817 ds.un("remove", this.updateInfo, this);
20818 ds.un("add", this.updateInfo, this);
20819 this.ds = undefined;
20823 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20824 * @param {Roo.data.Store} store The data store to bind
20826 bind : function(ds){
20827 ds.on("beforeload", this.beforeLoad, this);
20828 ds.on("load", this.onLoad, this);
20829 ds.on("loadexception", this.onLoadError, this);
20830 ds.on("remove", this.updateInfo, this);
20831 ds.on("add", this.updateInfo, this);
20842 * @class Roo.bootstrap.MessageBar
20843 * @extends Roo.bootstrap.Component
20844 * Bootstrap MessageBar class
20845 * @cfg {String} html contents of the MessageBar
20846 * @cfg {String} weight (info | success | warning | danger) default info
20847 * @cfg {String} beforeClass insert the bar before the given class
20848 * @cfg {Boolean} closable (true | false) default false
20849 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20852 * Create a new Element
20853 * @param {Object} config The config object
20856 Roo.bootstrap.MessageBar = function(config){
20857 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20860 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20866 beforeClass: 'bootstrap-sticky-wrap',
20868 getAutoCreate : function(){
20872 cls: 'alert alert-dismissable alert-' + this.weight,
20877 html: this.html || ''
20883 cfg.cls += ' alert-messages-fixed';
20897 onRender : function(ct, position)
20899 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20902 var cfg = Roo.apply({}, this.getAutoCreate());
20906 cfg.cls += ' ' + this.cls;
20909 cfg.style = this.style;
20911 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20913 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20916 this.el.select('>button.close').on('click', this.hide, this);
20922 if (!this.rendered) {
20928 this.fireEvent('show', this);
20934 if (!this.rendered) {
20940 this.fireEvent('hide', this);
20943 update : function()
20945 // var e = this.el.dom.firstChild;
20947 // if(this.closable){
20948 // e = e.nextSibling;
20951 // e.data = this.html || '';
20953 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20969 * @class Roo.bootstrap.Graph
20970 * @extends Roo.bootstrap.Component
20971 * Bootstrap Graph class
20975 @cfg {String} graphtype bar | vbar | pie
20976 @cfg {number} g_x coodinator | centre x (pie)
20977 @cfg {number} g_y coodinator | centre y (pie)
20978 @cfg {number} g_r radius (pie)
20979 @cfg {number} g_height height of the chart (respected by all elements in the set)
20980 @cfg {number} g_width width of the chart (respected by all elements in the set)
20981 @cfg {Object} title The title of the chart
20984 -opts (object) options for the chart
20986 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20987 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20989 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.
20990 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20992 o stretch (boolean)
20994 -opts (object) options for the pie
20997 o startAngle (number)
20998 o endAngle (number)
21002 * Create a new Input
21003 * @param {Object} config The config object
21006 Roo.bootstrap.Graph = function(config){
21007 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21013 * The img click event for the img.
21014 * @param {Roo.EventObject} e
21020 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21031 //g_colors: this.colors,
21038 getAutoCreate : function(){
21049 onRender : function(ct,position){
21050 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21051 this.raphael = Raphael(this.el.dom);
21053 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21054 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21055 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21056 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21058 r.text(160, 10, "Single Series Chart").attr(txtattr);
21059 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21060 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21061 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21063 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21064 r.barchart(330, 10, 300, 220, data1);
21065 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21066 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21069 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21070 // r.barchart(30, 30, 560, 250, xdata, {
21071 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21072 // axis : "0 0 1 1",
21073 // axisxlabels : xdata
21074 // //yvalues : cols,
21077 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21079 // this.load(null,xdata,{
21080 // axis : "0 0 1 1",
21081 // axisxlabels : xdata
21086 load : function(graphtype,xdata,opts){
21087 this.raphael.clear();
21089 graphtype = this.graphtype;
21094 var r = this.raphael,
21095 fin = function () {
21096 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21098 fout = function () {
21099 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21101 pfin = function() {
21102 this.sector.stop();
21103 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21106 this.label[0].stop();
21107 this.label[0].attr({ r: 7.5 });
21108 this.label[1].attr({ "font-weight": 800 });
21111 pfout = function() {
21112 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21115 this.label[0].animate({ r: 5 }, 500, "bounce");
21116 this.label[1].attr({ "font-weight": 400 });
21122 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21125 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21128 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21129 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21131 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21138 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21143 setTitle: function(o)
21148 initEvents: function() {
21151 this.el.on('click', this.onClick, this);
21155 onClick : function(e)
21157 Roo.log('img onclick');
21158 this.fireEvent('click', this, e);
21170 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21173 * @class Roo.bootstrap.dash.NumberBox
21174 * @extends Roo.bootstrap.Component
21175 * Bootstrap NumberBox class
21176 * @cfg {String} headline Box headline
21177 * @cfg {String} content Box content
21178 * @cfg {String} icon Box icon
21179 * @cfg {String} footer Footer text
21180 * @cfg {String} fhref Footer href
21183 * Create a new NumberBox
21184 * @param {Object} config The config object
21188 Roo.bootstrap.dash.NumberBox = function(config){
21189 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21193 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21202 getAutoCreate : function(){
21206 cls : 'small-box ',
21214 cls : 'roo-headline',
21215 html : this.headline
21219 cls : 'roo-content',
21220 html : this.content
21234 cls : 'ion ' + this.icon
21243 cls : 'small-box-footer',
21244 href : this.fhref || '#',
21248 cfg.cn.push(footer);
21255 onRender : function(ct,position){
21256 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21263 setHeadline: function (value)
21265 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21268 setFooter: function (value, href)
21270 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21273 this.el.select('a.small-box-footer',true).first().attr('href', href);
21278 setContent: function (value)
21280 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21283 initEvents: function()
21297 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21300 * @class Roo.bootstrap.dash.TabBox
21301 * @extends Roo.bootstrap.Component
21302 * Bootstrap TabBox class
21303 * @cfg {String} title Title of the TabBox
21304 * @cfg {String} icon Icon of the TabBox
21305 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21306 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21309 * Create a new TabBox
21310 * @param {Object} config The config object
21314 Roo.bootstrap.dash.TabBox = function(config){
21315 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21320 * When a pane is added
21321 * @param {Roo.bootstrap.dash.TabPane} pane
21325 * @event activatepane
21326 * When a pane is activated
21327 * @param {Roo.bootstrap.dash.TabPane} pane
21329 "activatepane" : true
21337 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21342 tabScrollable : false,
21344 getChildContainer : function()
21346 return this.el.select('.tab-content', true).first();
21349 getAutoCreate : function(){
21353 cls: 'pull-left header',
21361 cls: 'fa ' + this.icon
21367 cls: 'nav nav-tabs pull-right',
21373 if(this.tabScrollable){
21380 cls: 'nav nav-tabs pull-right',
21391 cls: 'nav-tabs-custom',
21396 cls: 'tab-content no-padding',
21404 initEvents : function()
21406 //Roo.log('add add pane handler');
21407 this.on('addpane', this.onAddPane, this);
21410 * Updates the box title
21411 * @param {String} html to set the title to.
21413 setTitle : function(value)
21415 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21417 onAddPane : function(pane)
21419 this.panes.push(pane);
21420 //Roo.log('addpane');
21422 // tabs are rendere left to right..
21423 if(!this.showtabs){
21427 var ctr = this.el.select('.nav-tabs', true).first();
21430 var existing = ctr.select('.nav-tab',true);
21431 var qty = existing.getCount();;
21434 var tab = ctr.createChild({
21436 cls : 'nav-tab' + (qty ? '' : ' active'),
21444 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21447 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21449 pane.el.addClass('active');
21454 onTabClick : function(ev,un,ob,pane)
21456 //Roo.log('tab - prev default');
21457 ev.preventDefault();
21460 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21461 pane.tab.addClass('active');
21462 //Roo.log(pane.title);
21463 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21464 // technically we should have a deactivate event.. but maybe add later.
21465 // and it should not de-activate the selected tab...
21466 this.fireEvent('activatepane', pane);
21467 pane.el.addClass('active');
21468 pane.fireEvent('activate');
21473 getActivePane : function()
21476 Roo.each(this.panes, function(p) {
21477 if(p.el.hasClass('active')){
21498 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21500 * @class Roo.bootstrap.TabPane
21501 * @extends Roo.bootstrap.Component
21502 * Bootstrap TabPane class
21503 * @cfg {Boolean} active (false | true) Default false
21504 * @cfg {String} title title of panel
21508 * Create a new TabPane
21509 * @param {Object} config The config object
21512 Roo.bootstrap.dash.TabPane = function(config){
21513 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21519 * When a pane is activated
21520 * @param {Roo.bootstrap.dash.TabPane} pane
21527 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21532 // the tabBox that this is attached to.
21535 getAutoCreate : function()
21543 cfg.cls += ' active';
21548 initEvents : function()
21550 //Roo.log('trigger add pane handler');
21551 this.parent().fireEvent('addpane', this)
21555 * Updates the tab title
21556 * @param {String} html to set the title to.
21558 setTitle: function(str)
21564 this.tab.select('a', true).first().dom.innerHTML = str;
21581 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21584 * @class Roo.bootstrap.menu.Menu
21585 * @extends Roo.bootstrap.Component
21586 * Bootstrap Menu class - container for Menu
21587 * @cfg {String} html Text of the menu
21588 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21589 * @cfg {String} icon Font awesome icon
21590 * @cfg {String} pos Menu align to (top | bottom) default bottom
21594 * Create a new Menu
21595 * @param {Object} config The config object
21599 Roo.bootstrap.menu.Menu = function(config){
21600 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21604 * @event beforeshow
21605 * Fires before this menu is displayed
21606 * @param {Roo.bootstrap.menu.Menu} this
21610 * @event beforehide
21611 * Fires before this menu is hidden
21612 * @param {Roo.bootstrap.menu.Menu} this
21617 * Fires after this menu is displayed
21618 * @param {Roo.bootstrap.menu.Menu} this
21623 * Fires after this menu is hidden
21624 * @param {Roo.bootstrap.menu.Menu} this
21629 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21630 * @param {Roo.bootstrap.menu.Menu} this
21631 * @param {Roo.EventObject} e
21638 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21642 weight : 'default',
21647 getChildContainer : function() {
21648 if(this.isSubMenu){
21652 return this.el.select('ul.dropdown-menu', true).first();
21655 getAutoCreate : function()
21660 cls : 'roo-menu-text',
21668 cls : 'fa ' + this.icon
21679 cls : 'dropdown-button btn btn-' + this.weight,
21684 cls : 'dropdown-toggle btn btn-' + this.weight,
21694 cls : 'dropdown-menu'
21700 if(this.pos == 'top'){
21701 cfg.cls += ' dropup';
21704 if(this.isSubMenu){
21707 cls : 'dropdown-menu'
21714 onRender : function(ct, position)
21716 this.isSubMenu = ct.hasClass('dropdown-submenu');
21718 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21721 initEvents : function()
21723 if(this.isSubMenu){
21727 this.hidden = true;
21729 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21730 this.triggerEl.on('click', this.onTriggerPress, this);
21732 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21733 this.buttonEl.on('click', this.onClick, this);
21739 if(this.isSubMenu){
21743 return this.el.select('ul.dropdown-menu', true).first();
21746 onClick : function(e)
21748 this.fireEvent("click", this, e);
21751 onTriggerPress : function(e)
21753 if (this.isVisible()) {
21760 isVisible : function(){
21761 return !this.hidden;
21766 this.fireEvent("beforeshow", this);
21768 this.hidden = false;
21769 this.el.addClass('open');
21771 Roo.get(document).on("mouseup", this.onMouseUp, this);
21773 this.fireEvent("show", this);
21780 this.fireEvent("beforehide", this);
21782 this.hidden = true;
21783 this.el.removeClass('open');
21785 Roo.get(document).un("mouseup", this.onMouseUp);
21787 this.fireEvent("hide", this);
21790 onMouseUp : function()
21804 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21807 * @class Roo.bootstrap.menu.Item
21808 * @extends Roo.bootstrap.Component
21809 * Bootstrap MenuItem class
21810 * @cfg {Boolean} submenu (true | false) default false
21811 * @cfg {String} html text of the item
21812 * @cfg {String} href the link
21813 * @cfg {Boolean} disable (true | false) default false
21814 * @cfg {Boolean} preventDefault (true | false) default true
21815 * @cfg {String} icon Font awesome icon
21816 * @cfg {String} pos Submenu align to (left | right) default right
21820 * Create a new Item
21821 * @param {Object} config The config object
21825 Roo.bootstrap.menu.Item = function(config){
21826 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21830 * Fires when the mouse is hovering over this menu
21831 * @param {Roo.bootstrap.menu.Item} this
21832 * @param {Roo.EventObject} e
21837 * Fires when the mouse exits this menu
21838 * @param {Roo.bootstrap.menu.Item} this
21839 * @param {Roo.EventObject} e
21845 * The raw click event for the entire grid.
21846 * @param {Roo.EventObject} e
21852 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21857 preventDefault: true,
21862 getAutoCreate : function()
21867 cls : 'roo-menu-item-text',
21875 cls : 'fa ' + this.icon
21884 href : this.href || '#',
21891 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21895 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21897 if(this.pos == 'left'){
21898 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21905 initEvents : function()
21907 this.el.on('mouseover', this.onMouseOver, this);
21908 this.el.on('mouseout', this.onMouseOut, this);
21910 this.el.select('a', true).first().on('click', this.onClick, this);
21914 onClick : function(e)
21916 if(this.preventDefault){
21917 e.preventDefault();
21920 this.fireEvent("click", this, e);
21923 onMouseOver : function(e)
21925 if(this.submenu && this.pos == 'left'){
21926 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21929 this.fireEvent("mouseover", this, e);
21932 onMouseOut : function(e)
21934 this.fireEvent("mouseout", this, e);
21946 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21949 * @class Roo.bootstrap.menu.Separator
21950 * @extends Roo.bootstrap.Component
21951 * Bootstrap Separator class
21954 * Create a new Separator
21955 * @param {Object} config The config object
21959 Roo.bootstrap.menu.Separator = function(config){
21960 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21963 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21965 getAutoCreate : function(){
21986 * @class Roo.bootstrap.Tooltip
21987 * Bootstrap Tooltip class
21988 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21989 * to determine which dom element triggers the tooltip.
21991 * It needs to add support for additional attributes like tooltip-position
21994 * Create a new Toolti
21995 * @param {Object} config The config object
21998 Roo.bootstrap.Tooltip = function(config){
21999 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22002 Roo.apply(Roo.bootstrap.Tooltip, {
22004 * @function init initialize tooltip monitoring.
22008 currentTip : false,
22009 currentRegion : false,
22015 Roo.get(document).on('mouseover', this.enter ,this);
22016 Roo.get(document).on('mouseout', this.leave, this);
22019 this.currentTip = new Roo.bootstrap.Tooltip();
22022 enter : function(ev)
22024 var dom = ev.getTarget();
22026 //Roo.log(['enter',dom]);
22027 var el = Roo.fly(dom);
22028 if (this.currentEl) {
22030 //Roo.log(this.currentEl);
22031 //Roo.log(this.currentEl.contains(dom));
22032 if (this.currentEl == el) {
22035 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22043 if (this.currentTip.el) {
22044 this.currentTip.el.hide(); // force hiding...
22049 // you can not look for children, as if el is the body.. then everythign is the child..
22050 if (!el.attr('tooltip')) { //
22051 if (!el.select("[tooltip]").elements.length) {
22054 // is the mouse over this child...?
22055 bindEl = el.select("[tooltip]").first();
22056 var xy = ev.getXY();
22057 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22058 //Roo.log("not in region.");
22061 //Roo.log("child element over..");
22064 this.currentEl = bindEl;
22065 this.currentTip.bind(bindEl);
22066 this.currentRegion = Roo.lib.Region.getRegion(dom);
22067 this.currentTip.enter();
22070 leave : function(ev)
22072 var dom = ev.getTarget();
22073 //Roo.log(['leave',dom]);
22074 if (!this.currentEl) {
22079 if (dom != this.currentEl.dom) {
22082 var xy = ev.getXY();
22083 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22086 // only activate leave if mouse cursor is outside... bounding box..
22091 if (this.currentTip) {
22092 this.currentTip.leave();
22094 //Roo.log('clear currentEl');
22095 this.currentEl = false;
22100 'left' : ['r-l', [-2,0], 'right'],
22101 'right' : ['l-r', [2,0], 'left'],
22102 'bottom' : ['t-b', [0,2], 'top'],
22103 'top' : [ 'b-t', [0,-2], 'bottom']
22109 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22114 delay : null, // can be { show : 300 , hide: 500}
22118 hoverState : null, //???
22120 placement : 'bottom',
22122 getAutoCreate : function(){
22129 cls : 'tooltip-arrow'
22132 cls : 'tooltip-inner'
22139 bind : function(el)
22145 enter : function () {
22147 if (this.timeout != null) {
22148 clearTimeout(this.timeout);
22151 this.hoverState = 'in';
22152 //Roo.log("enter - show");
22153 if (!this.delay || !this.delay.show) {
22158 this.timeout = setTimeout(function () {
22159 if (_t.hoverState == 'in') {
22162 }, this.delay.show);
22166 clearTimeout(this.timeout);
22168 this.hoverState = 'out';
22169 if (!this.delay || !this.delay.hide) {
22175 this.timeout = setTimeout(function () {
22176 //Roo.log("leave - timeout");
22178 if (_t.hoverState == 'out') {
22180 Roo.bootstrap.Tooltip.currentEl = false;
22188 this.render(document.body);
22191 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22193 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22195 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22197 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22199 var placement = typeof this.placement == 'function' ?
22200 this.placement.call(this, this.el, on_el) :
22203 var autoToken = /\s?auto?\s?/i;
22204 var autoPlace = autoToken.test(placement);
22206 placement = placement.replace(autoToken, '') || 'top';
22210 //this.el.setXY([0,0]);
22212 //this.el.dom.style.display='block';
22213 this.el.addClass(placement);
22215 //this.el.appendTo(on_el);
22217 var p = this.getPosition();
22218 var box = this.el.getBox();
22223 var align = Roo.bootstrap.Tooltip.alignment[placement];
22224 this.el.alignTo(this.bindEl, align[0],align[1]);
22225 //var arrow = this.el.select('.arrow',true).first();
22226 //arrow.set(align[2],
22228 this.el.addClass('in fade');
22229 this.hoverState = null;
22231 if (this.el.hasClass('fade')) {
22242 //this.el.setXY([0,0]);
22243 this.el.removeClass('in');
22259 * @class Roo.bootstrap.LocationPicker
22260 * @extends Roo.bootstrap.Component
22261 * Bootstrap LocationPicker class
22262 * @cfg {Number} latitude Position when init default 0
22263 * @cfg {Number} longitude Position when init default 0
22264 * @cfg {Number} zoom default 15
22265 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22266 * @cfg {Boolean} mapTypeControl default false
22267 * @cfg {Boolean} disableDoubleClickZoom default false
22268 * @cfg {Boolean} scrollwheel default true
22269 * @cfg {Boolean} streetViewControl default false
22270 * @cfg {Number} radius default 0
22271 * @cfg {String} locationName
22272 * @cfg {Boolean} draggable default true
22273 * @cfg {Boolean} enableAutocomplete default false
22274 * @cfg {Boolean} enableReverseGeocode default true
22275 * @cfg {String} markerTitle
22278 * Create a new LocationPicker
22279 * @param {Object} config The config object
22283 Roo.bootstrap.LocationPicker = function(config){
22285 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22290 * Fires when the picker initialized.
22291 * @param {Roo.bootstrap.LocationPicker} this
22292 * @param {Google Location} location
22296 * @event positionchanged
22297 * Fires when the picker position changed.
22298 * @param {Roo.bootstrap.LocationPicker} this
22299 * @param {Google Location} location
22301 positionchanged : true,
22304 * Fires when the map resize.
22305 * @param {Roo.bootstrap.LocationPicker} this
22310 * Fires when the map show.
22311 * @param {Roo.bootstrap.LocationPicker} this
22316 * Fires when the map hide.
22317 * @param {Roo.bootstrap.LocationPicker} this
22322 * Fires when click the map.
22323 * @param {Roo.bootstrap.LocationPicker} this
22324 * @param {Map event} e
22328 * @event mapRightClick
22329 * Fires when right click the map.
22330 * @param {Roo.bootstrap.LocationPicker} this
22331 * @param {Map event} e
22333 mapRightClick : true,
22335 * @event markerClick
22336 * Fires when click the marker.
22337 * @param {Roo.bootstrap.LocationPicker} this
22338 * @param {Map event} e
22340 markerClick : true,
22342 * @event markerRightClick
22343 * Fires when right click the marker.
22344 * @param {Roo.bootstrap.LocationPicker} this
22345 * @param {Map event} e
22347 markerRightClick : true,
22349 * @event OverlayViewDraw
22350 * Fires when OverlayView Draw
22351 * @param {Roo.bootstrap.LocationPicker} this
22353 OverlayViewDraw : true,
22355 * @event OverlayViewOnAdd
22356 * Fires when OverlayView Draw
22357 * @param {Roo.bootstrap.LocationPicker} this
22359 OverlayViewOnAdd : true,
22361 * @event OverlayViewOnRemove
22362 * Fires when OverlayView Draw
22363 * @param {Roo.bootstrap.LocationPicker} this
22365 OverlayViewOnRemove : true,
22367 * @event OverlayViewShow
22368 * Fires when OverlayView Draw
22369 * @param {Roo.bootstrap.LocationPicker} this
22370 * @param {Pixel} cpx
22372 OverlayViewShow : true,
22374 * @event OverlayViewHide
22375 * Fires when OverlayView Draw
22376 * @param {Roo.bootstrap.LocationPicker} this
22378 OverlayViewHide : true
22383 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22385 gMapContext: false,
22391 mapTypeControl: false,
22392 disableDoubleClickZoom: false,
22394 streetViewControl: false,
22398 enableAutocomplete: false,
22399 enableReverseGeocode: true,
22402 getAutoCreate: function()
22407 cls: 'roo-location-picker'
22413 initEvents: function(ct, position)
22415 if(!this.el.getWidth() || this.isApplied()){
22419 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22424 initial: function()
22426 if(!this.mapTypeId){
22427 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22430 this.gMapContext = this.GMapContext();
22432 this.initOverlayView();
22434 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22438 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22439 _this.setPosition(_this.gMapContext.marker.position);
22442 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22443 _this.fireEvent('mapClick', this, event);
22447 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22448 _this.fireEvent('mapRightClick', this, event);
22452 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22453 _this.fireEvent('markerClick', this, event);
22457 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22458 _this.fireEvent('markerRightClick', this, event);
22462 this.setPosition(this.gMapContext.location);
22464 this.fireEvent('initial', this, this.gMapContext.location);
22467 initOverlayView: function()
22471 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22475 _this.fireEvent('OverlayViewDraw', _this);
22480 _this.fireEvent('OverlayViewOnAdd', _this);
22483 onRemove: function()
22485 _this.fireEvent('OverlayViewOnRemove', _this);
22488 show: function(cpx)
22490 _this.fireEvent('OverlayViewShow', _this, cpx);
22495 _this.fireEvent('OverlayViewHide', _this);
22501 fromLatLngToContainerPixel: function(event)
22503 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22506 isApplied: function()
22508 return this.getGmapContext() == false ? false : true;
22511 getGmapContext: function()
22513 return this.gMapContext
22516 GMapContext: function()
22518 var position = new google.maps.LatLng(this.latitude, this.longitude);
22520 var _map = new google.maps.Map(this.el.dom, {
22523 mapTypeId: this.mapTypeId,
22524 mapTypeControl: this.mapTypeControl,
22525 disableDoubleClickZoom: this.disableDoubleClickZoom,
22526 scrollwheel: this.scrollwheel,
22527 streetViewControl: this.streetViewControl,
22528 locationName: this.locationName,
22529 draggable: this.draggable,
22530 enableAutocomplete: this.enableAutocomplete,
22531 enableReverseGeocode: this.enableReverseGeocode
22534 var _marker = new google.maps.Marker({
22535 position: position,
22537 title: this.markerTitle,
22538 draggable: this.draggable
22545 location: position,
22546 radius: this.radius,
22547 locationName: this.locationName,
22548 addressComponents: {
22549 formatted_address: null,
22550 addressLine1: null,
22551 addressLine2: null,
22553 streetNumber: null,
22557 stateOrProvince: null
22560 domContainer: this.el.dom,
22561 geodecoder: new google.maps.Geocoder()
22565 drawCircle: function(center, radius, options)
22567 if (this.gMapContext.circle != null) {
22568 this.gMapContext.circle.setMap(null);
22572 options = Roo.apply({}, options, {
22573 strokeColor: "#0000FF",
22574 strokeOpacity: .35,
22576 fillColor: "#0000FF",
22580 options.map = this.gMapContext.map;
22581 options.radius = radius;
22582 options.center = center;
22583 this.gMapContext.circle = new google.maps.Circle(options);
22584 return this.gMapContext.circle;
22590 setPosition: function(location)
22592 this.gMapContext.location = location;
22593 this.gMapContext.marker.setPosition(location);
22594 this.gMapContext.map.panTo(location);
22595 this.drawCircle(location, this.gMapContext.radius, {});
22599 if (this.gMapContext.settings.enableReverseGeocode) {
22600 this.gMapContext.geodecoder.geocode({
22601 latLng: this.gMapContext.location
22602 }, function(results, status) {
22604 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22605 _this.gMapContext.locationName = results[0].formatted_address;
22606 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22608 _this.fireEvent('positionchanged', this, location);
22615 this.fireEvent('positionchanged', this, location);
22620 google.maps.event.trigger(this.gMapContext.map, "resize");
22622 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22624 this.fireEvent('resize', this);
22627 setPositionByLatLng: function(latitude, longitude)
22629 this.setPosition(new google.maps.LatLng(latitude, longitude));
22632 getCurrentPosition: function()
22635 latitude: this.gMapContext.location.lat(),
22636 longitude: this.gMapContext.location.lng()
22640 getAddressName: function()
22642 return this.gMapContext.locationName;
22645 getAddressComponents: function()
22647 return this.gMapContext.addressComponents;
22650 address_component_from_google_geocode: function(address_components)
22654 for (var i = 0; i < address_components.length; i++) {
22655 var component = address_components[i];
22656 if (component.types.indexOf("postal_code") >= 0) {
22657 result.postalCode = component.short_name;
22658 } else if (component.types.indexOf("street_number") >= 0) {
22659 result.streetNumber = component.short_name;
22660 } else if (component.types.indexOf("route") >= 0) {
22661 result.streetName = component.short_name;
22662 } else if (component.types.indexOf("neighborhood") >= 0) {
22663 result.city = component.short_name;
22664 } else if (component.types.indexOf("locality") >= 0) {
22665 result.city = component.short_name;
22666 } else if (component.types.indexOf("sublocality") >= 0) {
22667 result.district = component.short_name;
22668 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22669 result.stateOrProvince = component.short_name;
22670 } else if (component.types.indexOf("country") >= 0) {
22671 result.country = component.short_name;
22675 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22676 result.addressLine2 = "";
22680 setZoomLevel: function(zoom)
22682 this.gMapContext.map.setZoom(zoom);
22695 this.fireEvent('show', this);
22706 this.fireEvent('hide', this);
22711 Roo.apply(Roo.bootstrap.LocationPicker, {
22713 OverlayView : function(map, options)
22715 options = options || {};
22729 * @class Roo.bootstrap.Alert
22730 * @extends Roo.bootstrap.Component
22731 * Bootstrap Alert class
22732 * @cfg {String} title The title of alert
22733 * @cfg {String} html The content of alert
22734 * @cfg {String} weight ( success | info | warning | danger )
22735 * @cfg {String} faicon font-awesomeicon
22738 * Create a new alert
22739 * @param {Object} config The config object
22743 Roo.bootstrap.Alert = function(config){
22744 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22748 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22755 getAutoCreate : function()
22764 cls : 'roo-alert-icon'
22769 cls : 'roo-alert-title',
22774 cls : 'roo-alert-text',
22781 cfg.cn[0].cls += ' fa ' + this.faicon;
22785 cfg.cls += ' alert-' + this.weight;
22791 initEvents: function()
22793 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22796 setTitle : function(str)
22798 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22801 setText : function(str)
22803 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22806 setWeight : function(weight)
22809 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22812 this.weight = weight;
22814 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22817 setIcon : function(icon)
22820 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22825 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);