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(){
4221 * @class Roo.bootstrap.Pagination
4222 * @extends Roo.bootstrap.Component
4223 * Bootstrap Pagination class
4224 * @cfg {String} size xs | sm | md | lg
4225 * @cfg {Boolean} inverse false | true
4228 * Create a new Pagination
4229 * @param {Object} config The config object
4232 Roo.bootstrap.Pagination = function(config){
4233 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4236 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4242 getAutoCreate : function(){
4248 cfg.cls += ' inverse';
4254 cfg.cls += " " + this.cls;
4272 * @class Roo.bootstrap.PaginationItem
4273 * @extends Roo.bootstrap.Component
4274 * Bootstrap PaginationItem class
4275 * @cfg {String} html text
4276 * @cfg {String} href the link
4277 * @cfg {Boolean} preventDefault (true | false) default true
4278 * @cfg {Boolean} active (true | false) default false
4279 * @cfg {Boolean} disabled default false
4283 * Create a new PaginationItem
4284 * @param {Object} config The config object
4288 Roo.bootstrap.PaginationItem = function(config){
4289 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4294 * The raw click event for the entire grid.
4295 * @param {Roo.EventObject} e
4301 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4305 preventDefault: true,
4310 getAutoCreate : function(){
4316 href : this.href ? this.href : '#',
4317 html : this.html ? this.html : ''
4327 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4331 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4337 initEvents: function() {
4339 this.el.on('click', this.onClick, this);
4342 onClick : function(e)
4344 Roo.log('PaginationItem on click ');
4345 if(this.preventDefault){
4353 this.fireEvent('click', this, e);
4369 * @class Roo.bootstrap.Slider
4370 * @extends Roo.bootstrap.Component
4371 * Bootstrap Slider class
4374 * Create a new Slider
4375 * @param {Object} config The config object
4378 Roo.bootstrap.Slider = function(config){
4379 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4382 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4384 getAutoCreate : function(){
4388 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4392 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4404 * Ext JS Library 1.1.1
4405 * Copyright(c) 2006-2007, Ext JS, LLC.
4407 * Originally Released Under LGPL - original licence link has changed is not relivant.
4410 * <script type="text/javascript">
4415 * @class Roo.grid.ColumnModel
4416 * @extends Roo.util.Observable
4417 * This is the default implementation of a ColumnModel used by the Grid. It defines
4418 * the columns in the grid.
4421 var colModel = new Roo.grid.ColumnModel([
4422 {header: "Ticker", width: 60, sortable: true, locked: true},
4423 {header: "Company Name", width: 150, sortable: true},
4424 {header: "Market Cap.", width: 100, sortable: true},
4425 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4426 {header: "Employees", width: 100, sortable: true, resizable: false}
4431 * The config options listed for this class are options which may appear in each
4432 * individual column definition.
4433 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4435 * @param {Object} config An Array of column config objects. See this class's
4436 * config objects for details.
4438 Roo.grid.ColumnModel = function(config){
4440 * The config passed into the constructor
4442 this.config = config;
4445 // if no id, create one
4446 // if the column does not have a dataIndex mapping,
4447 // map it to the order it is in the config
4448 for(var i = 0, len = config.length; i < len; i++){
4450 if(typeof c.dataIndex == "undefined"){
4453 if(typeof c.renderer == "string"){
4454 c.renderer = Roo.util.Format[c.renderer];
4456 if(typeof c.id == "undefined"){
4459 if(c.editor && c.editor.xtype){
4460 c.editor = Roo.factory(c.editor, Roo.grid);
4462 if(c.editor && c.editor.isFormField){
4463 c.editor = new Roo.grid.GridEditor(c.editor);
4465 this.lookup[c.id] = c;
4469 * The width of columns which have no width specified (defaults to 100)
4472 this.defaultWidth = 100;
4475 * Default sortable of columns which have no sortable specified (defaults to false)
4478 this.defaultSortable = false;
4482 * @event widthchange
4483 * Fires when the width of a column changes.
4484 * @param {ColumnModel} this
4485 * @param {Number} columnIndex The column index
4486 * @param {Number} newWidth The new width
4488 "widthchange": true,
4490 * @event headerchange
4491 * Fires when the text of a header changes.
4492 * @param {ColumnModel} this
4493 * @param {Number} columnIndex The column index
4494 * @param {Number} newText The new header text
4496 "headerchange": true,
4498 * @event hiddenchange
4499 * Fires when a column is hidden or "unhidden".
4500 * @param {ColumnModel} this
4501 * @param {Number} columnIndex The column index
4502 * @param {Boolean} hidden true if hidden, false otherwise
4504 "hiddenchange": true,
4506 * @event columnmoved
4507 * Fires when a column is moved.
4508 * @param {ColumnModel} this
4509 * @param {Number} oldIndex
4510 * @param {Number} newIndex
4512 "columnmoved" : true,
4514 * @event columlockchange
4515 * Fires when a column's locked state is changed
4516 * @param {ColumnModel} this
4517 * @param {Number} colIndex
4518 * @param {Boolean} locked true if locked
4520 "columnlockchange" : true
4522 Roo.grid.ColumnModel.superclass.constructor.call(this);
4524 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4526 * @cfg {String} header The header text to display in the Grid view.
4529 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4530 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4531 * specified, the column's index is used as an index into the Record's data Array.
4534 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4535 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4538 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4539 * Defaults to the value of the {@link #defaultSortable} property.
4540 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4543 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4546 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4549 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4552 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4555 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4556 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4557 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4558 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4561 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4564 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4567 * @cfg {String} cursor (Optional)
4570 * @cfg {String} tooltip (Optional)
4573 * Returns the id of the column at the specified index.
4574 * @param {Number} index The column index
4575 * @return {String} the id
4577 getColumnId : function(index){
4578 return this.config[index].id;
4582 * Returns the column for a specified id.
4583 * @param {String} id The column id
4584 * @return {Object} the column
4586 getColumnById : function(id){
4587 return this.lookup[id];
4592 * Returns the column for a specified dataIndex.
4593 * @param {String} dataIndex The column dataIndex
4594 * @return {Object|Boolean} the column or false if not found
4596 getColumnByDataIndex: function(dataIndex){
4597 var index = this.findColumnIndex(dataIndex);
4598 return index > -1 ? this.config[index] : false;
4602 * Returns the index for a specified column id.
4603 * @param {String} id The column id
4604 * @return {Number} the index, or -1 if not found
4606 getIndexById : function(id){
4607 for(var i = 0, len = this.config.length; i < len; i++){
4608 if(this.config[i].id == id){
4616 * Returns the index for a specified column dataIndex.
4617 * @param {String} dataIndex The column dataIndex
4618 * @return {Number} the index, or -1 if not found
4621 findColumnIndex : function(dataIndex){
4622 for(var i = 0, len = this.config.length; i < len; i++){
4623 if(this.config[i].dataIndex == dataIndex){
4631 moveColumn : function(oldIndex, newIndex){
4632 var c = this.config[oldIndex];
4633 this.config.splice(oldIndex, 1);
4634 this.config.splice(newIndex, 0, c);
4635 this.dataMap = null;
4636 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4639 isLocked : function(colIndex){
4640 return this.config[colIndex].locked === true;
4643 setLocked : function(colIndex, value, suppressEvent){
4644 if(this.isLocked(colIndex) == value){
4647 this.config[colIndex].locked = value;
4649 this.fireEvent("columnlockchange", this, colIndex, value);
4653 getTotalLockedWidth : function(){
4655 for(var i = 0; i < this.config.length; i++){
4656 if(this.isLocked(i) && !this.isHidden(i)){
4657 this.totalWidth += this.getColumnWidth(i);
4663 getLockedCount : function(){
4664 for(var i = 0, len = this.config.length; i < len; i++){
4665 if(!this.isLocked(i)){
4672 * Returns the number of columns.
4675 getColumnCount : function(visibleOnly){
4676 if(visibleOnly === true){
4678 for(var i = 0, len = this.config.length; i < len; i++){
4679 if(!this.isHidden(i)){
4685 return this.config.length;
4689 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4690 * @param {Function} fn
4691 * @param {Object} scope (optional)
4692 * @return {Array} result
4694 getColumnsBy : function(fn, scope){
4696 for(var i = 0, len = this.config.length; i < len; i++){
4697 var c = this.config[i];
4698 if(fn.call(scope||this, c, i) === true){
4706 * Returns true if the specified column is sortable.
4707 * @param {Number} col The column index
4710 isSortable : function(col){
4711 if(typeof this.config[col].sortable == "undefined"){
4712 return this.defaultSortable;
4714 return this.config[col].sortable;
4718 * Returns the rendering (formatting) function defined for the column.
4719 * @param {Number} col The column index.
4720 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4722 getRenderer : function(col){
4723 if(!this.config[col].renderer){
4724 return Roo.grid.ColumnModel.defaultRenderer;
4726 return this.config[col].renderer;
4730 * Sets the rendering (formatting) function for a column.
4731 * @param {Number} col The column index
4732 * @param {Function} fn The function to use to process the cell's raw data
4733 * to return HTML markup for the grid view. The render function is called with
4734 * the following parameters:<ul>
4735 * <li>Data value.</li>
4736 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4737 * <li>css A CSS style string to apply to the table cell.</li>
4738 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4739 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4740 * <li>Row index</li>
4741 * <li>Column index</li>
4742 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4744 setRenderer : function(col, fn){
4745 this.config[col].renderer = fn;
4749 * Returns the width for the specified column.
4750 * @param {Number} col The column index
4753 getColumnWidth : function(col){
4754 return this.config[col].width * 1 || this.defaultWidth;
4758 * Sets the width for a column.
4759 * @param {Number} col The column index
4760 * @param {Number} width The new width
4762 setColumnWidth : function(col, width, suppressEvent){
4763 this.config[col].width = width;
4764 this.totalWidth = null;
4766 this.fireEvent("widthchange", this, col, width);
4771 * Returns the total width of all columns.
4772 * @param {Boolean} includeHidden True to include hidden column widths
4775 getTotalWidth : function(includeHidden){
4776 if(!this.totalWidth){
4777 this.totalWidth = 0;
4778 for(var i = 0, len = this.config.length; i < len; i++){
4779 if(includeHidden || !this.isHidden(i)){
4780 this.totalWidth += this.getColumnWidth(i);
4784 return this.totalWidth;
4788 * Returns the header for the specified column.
4789 * @param {Number} col The column index
4792 getColumnHeader : function(col){
4793 return this.config[col].header;
4797 * Sets the header for a column.
4798 * @param {Number} col The column index
4799 * @param {String} header The new header
4801 setColumnHeader : function(col, header){
4802 this.config[col].header = header;
4803 this.fireEvent("headerchange", this, col, header);
4807 * Returns the tooltip for the specified column.
4808 * @param {Number} col The column index
4811 getColumnTooltip : function(col){
4812 return this.config[col].tooltip;
4815 * Sets the tooltip for a column.
4816 * @param {Number} col The column index
4817 * @param {String} tooltip The new tooltip
4819 setColumnTooltip : function(col, tooltip){
4820 this.config[col].tooltip = tooltip;
4824 * Returns the dataIndex for the specified column.
4825 * @param {Number} col The column index
4828 getDataIndex : function(col){
4829 return this.config[col].dataIndex;
4833 * Sets the dataIndex for a column.
4834 * @param {Number} col The column index
4835 * @param {Number} dataIndex The new dataIndex
4837 setDataIndex : function(col, dataIndex){
4838 this.config[col].dataIndex = dataIndex;
4844 * Returns true if the cell is editable.
4845 * @param {Number} colIndex The column index
4846 * @param {Number} rowIndex The row index
4849 isCellEditable : function(colIndex, rowIndex){
4850 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4854 * Returns the editor defined for the cell/column.
4855 * return false or null to disable editing.
4856 * @param {Number} colIndex The column index
4857 * @param {Number} rowIndex The row index
4860 getCellEditor : function(colIndex, rowIndex){
4861 return this.config[colIndex].editor;
4865 * Sets if a column is editable.
4866 * @param {Number} col The column index
4867 * @param {Boolean} editable True if the column is editable
4869 setEditable : function(col, editable){
4870 this.config[col].editable = editable;
4875 * Returns true if the column is hidden.
4876 * @param {Number} colIndex The column index
4879 isHidden : function(colIndex){
4880 return this.config[colIndex].hidden;
4885 * Returns true if the column width cannot be changed
4887 isFixed : function(colIndex){
4888 return this.config[colIndex].fixed;
4892 * Returns true if the column can be resized
4895 isResizable : function(colIndex){
4896 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4899 * Sets if a column is hidden.
4900 * @param {Number} colIndex The column index
4901 * @param {Boolean} hidden True if the column is hidden
4903 setHidden : function(colIndex, hidden){
4904 this.config[colIndex].hidden = hidden;
4905 this.totalWidth = null;
4906 this.fireEvent("hiddenchange", this, colIndex, hidden);
4910 * Sets the editor for a column.
4911 * @param {Number} col The column index
4912 * @param {Object} editor The editor object
4914 setEditor : function(col, editor){
4915 this.config[col].editor = editor;
4919 Roo.grid.ColumnModel.defaultRenderer = function(value){
4920 if(typeof value == "string" && value.length < 1){
4926 // Alias for backwards compatibility
4927 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4930 * Ext JS Library 1.1.1
4931 * Copyright(c) 2006-2007, Ext JS, LLC.
4933 * Originally Released Under LGPL - original licence link has changed is not relivant.
4936 * <script type="text/javascript">
4940 * @class Roo.LoadMask
4941 * A simple utility class for generically masking elements while loading data. If the element being masked has
4942 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4943 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4944 * element's UpdateManager load indicator and will be destroyed after the initial load.
4946 * Create a new LoadMask
4947 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4948 * @param {Object} config The config object
4950 Roo.LoadMask = function(el, config){
4951 this.el = Roo.get(el);
4952 Roo.apply(this, config);
4954 this.store.on('beforeload', this.onBeforeLoad, this);
4955 this.store.on('load', this.onLoad, this);
4956 this.store.on('loadexception', this.onLoadException, this);
4957 this.removeMask = false;
4959 var um = this.el.getUpdateManager();
4960 um.showLoadIndicator = false; // disable the default indicator
4961 um.on('beforeupdate', this.onBeforeLoad, this);
4962 um.on('update', this.onLoad, this);
4963 um.on('failure', this.onLoad, this);
4964 this.removeMask = true;
4968 Roo.LoadMask.prototype = {
4970 * @cfg {Boolean} removeMask
4971 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4972 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4976 * The text to display in a centered loading message box (defaults to 'Loading...')
4980 * @cfg {String} msgCls
4981 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4983 msgCls : 'x-mask-loading',
4986 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4992 * Disables the mask to prevent it from being displayed
4994 disable : function(){
4995 this.disabled = true;
4999 * Enables the mask so that it can be displayed
5001 enable : function(){
5002 this.disabled = false;
5005 onLoadException : function()
5009 if (typeof(arguments[3]) != 'undefined') {
5010 Roo.MessageBox.alert("Error loading",arguments[3]);
5014 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5015 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5024 this.el.unmask(this.removeMask);
5029 this.el.unmask(this.removeMask);
5033 onBeforeLoad : function(){
5035 this.el.mask(this.msg, this.msgCls);
5040 destroy : function(){
5042 this.store.un('beforeload', this.onBeforeLoad, this);
5043 this.store.un('load', this.onLoad, this);
5044 this.store.un('loadexception', this.onLoadException, this);
5046 var um = this.el.getUpdateManager();
5047 um.un('beforeupdate', this.onBeforeLoad, this);
5048 um.un('update', this.onLoad, this);
5049 um.un('failure', this.onLoad, this);
5060 * @class Roo.bootstrap.Table
5061 * @extends Roo.bootstrap.Component
5062 * Bootstrap Table class
5063 * @cfg {String} cls table class
5064 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5065 * @cfg {String} bgcolor Specifies the background color for a table
5066 * @cfg {Number} border Specifies whether the table cells should have borders or not
5067 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5068 * @cfg {Number} cellspacing Specifies the space between cells
5069 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5070 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5071 * @cfg {String} sortable Specifies that the table should be sortable
5072 * @cfg {String} summary Specifies a summary of the content of a table
5073 * @cfg {Number} width Specifies the width of a table
5074 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5076 * @cfg {boolean} striped Should the rows be alternative striped
5077 * @cfg {boolean} bordered Add borders to the table
5078 * @cfg {boolean} hover Add hover highlighting
5079 * @cfg {boolean} condensed Format condensed
5080 * @cfg {boolean} responsive Format condensed
5081 * @cfg {Boolean} loadMask (true|false) default false
5082 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5083 * @cfg {Boolean} thead (true|false) generate thead, default true
5084 * @cfg {Boolean} RowSelection (true|false) default false
5085 * @cfg {Boolean} CellSelection (true|false) default false
5086 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5090 * Create a new Table
5091 * @param {Object} config The config object
5094 Roo.bootstrap.Table = function(config){
5095 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5098 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5099 this.sm = this.selModel;
5100 this.sm.xmodule = this.xmodule || false;
5102 if (this.cm && typeof(this.cm.config) == 'undefined') {
5103 this.colModel = new Roo.grid.ColumnModel(this.cm);
5104 this.cm = this.colModel;
5105 this.cm.xmodule = this.xmodule || false;
5108 this.store= Roo.factory(this.store, Roo.data);
5109 this.ds = this.store;
5110 this.ds.xmodule = this.xmodule || false;
5113 if (this.footer && this.store) {
5114 this.footer.dataSource = this.ds;
5115 this.footer = Roo.factory(this.footer);
5122 * Fires when a cell is clicked
5123 * @param {Roo.bootstrap.Table} this
5124 * @param {Roo.Element} el
5125 * @param {Number} rowIndex
5126 * @param {Number} columnIndex
5127 * @param {Roo.EventObject} e
5131 * @event celldblclick
5132 * Fires when a cell is double 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
5139 "celldblclick" : true,
5142 * Fires when a row is clicked
5143 * @param {Roo.bootstrap.Table} this
5144 * @param {Roo.Element} el
5145 * @param {Number} rowIndex
5146 * @param {Roo.EventObject} e
5150 * @event rowdblclick
5151 * Fires when a row is double clicked
5152 * @param {Roo.bootstrap.Table} this
5153 * @param {Roo.Element} el
5154 * @param {Number} rowIndex
5155 * @param {Roo.EventObject} e
5157 "rowdblclick" : true,
5160 * Fires when a mouseover occur
5161 * @param {Roo.bootstrap.Table} this
5162 * @param {Roo.Element} el
5163 * @param {Number} rowIndex
5164 * @param {Number} columnIndex
5165 * @param {Roo.EventObject} e
5170 * Fires when a mouseout 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 row is rendered, so you can change add a style to it.
5181 * @param {Roo.bootstrap.Table} this
5182 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5186 * @event rowsrendered
5187 * Fires when all the rows have been rendered
5188 * @param {Roo.bootstrap.Table} this
5190 'rowsrendered' : true
5195 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5219 RowSelection : false,
5220 CellSelection : false,
5223 // Roo.Element - the tbody
5226 getAutoCreate : function(){
5227 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5236 cfg.cls += ' table-striped';
5240 cfg.cls += ' table-hover';
5242 if (this.bordered) {
5243 cfg.cls += ' table-bordered';
5245 if (this.condensed) {
5246 cfg.cls += ' table-condensed';
5248 if (this.responsive) {
5249 cfg.cls += ' table-responsive';
5253 cfg.cls+= ' ' +this.cls;
5256 // this lot should be simplifed...
5259 cfg.align=this.align;
5262 cfg.bgcolor=this.bgcolor;
5265 cfg.border=this.border;
5267 if (this.cellpadding) {
5268 cfg.cellpadding=this.cellpadding;
5270 if (this.cellspacing) {
5271 cfg.cellspacing=this.cellspacing;
5274 cfg.frame=this.frame;
5277 cfg.rules=this.rules;
5279 if (this.sortable) {
5280 cfg.sortable=this.sortable;
5283 cfg.summary=this.summary;
5286 cfg.width=this.width;
5289 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5292 if(this.store || this.cm){
5294 cfg.cn.push(this.renderHeader());
5297 cfg.cn.push(this.renderBody());
5300 cfg.cn.push(this.renderFooter());
5303 cfg.cls+= ' TableGrid';
5306 return { cn : [ cfg ] };
5309 initEvents : function()
5311 if(!this.store || !this.cm){
5315 //Roo.log('initEvents with ds!!!!');
5317 this.mainBody = this.el.select('tbody', true).first();
5322 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5323 e.on('click', _this.sort, _this);
5326 this.el.on("click", this.onClick, this);
5327 this.el.on("dblclick", this.onDblClick, this);
5329 // why is this done????? = it breaks dialogs??
5330 //this.parent().el.setStyle('position', 'relative');
5334 this.footer.parentId = this.id;
5335 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5338 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5340 this.store.on('load', this.onLoad, this);
5341 this.store.on('beforeload', this.onBeforeLoad, this);
5342 this.store.on('update', this.onUpdate, this);
5343 this.store.on('add', this.onAdd, this);
5347 onMouseover : function(e, el)
5349 var cell = Roo.get(el);
5355 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5356 cell = cell.findParent('td', false, true);
5359 var row = cell.findParent('tr', false, true);
5360 var cellIndex = cell.dom.cellIndex;
5361 var rowIndex = row.dom.rowIndex - 1; // start from 0
5363 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5367 onMouseout : function(e, el)
5369 var cell = Roo.get(el);
5375 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5376 cell = cell.findParent('td', false, true);
5379 var row = cell.findParent('tr', false, true);
5380 var cellIndex = cell.dom.cellIndex;
5381 var rowIndex = row.dom.rowIndex - 1; // start from 0
5383 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5387 onClick : function(e, el)
5389 var cell = Roo.get(el);
5391 if(!cell || (!this.CellSelection && !this.RowSelection)){
5395 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5396 cell = cell.findParent('td', false, true);
5399 if(!cell || typeof(cell) == 'undefined'){
5403 var row = cell.findParent('tr', false, true);
5405 if(!row || typeof(row) == 'undefined'){
5409 var cellIndex = cell.dom.cellIndex;
5410 var rowIndex = this.getRowIndex(row);
5412 if(this.CellSelection){
5413 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5416 if(this.RowSelection){
5417 this.fireEvent('rowclick', this, row, rowIndex, e);
5423 onDblClick : function(e,el)
5425 var cell = Roo.get(el);
5427 if(!cell || (!this.CellSelection && !this.RowSelection)){
5431 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5432 cell = cell.findParent('td', false, true);
5435 if(!cell || typeof(cell) == 'undefined'){
5439 var row = cell.findParent('tr', false, true);
5441 if(!row || typeof(row) == 'undefined'){
5445 var cellIndex = cell.dom.cellIndex;
5446 var rowIndex = this.getRowIndex(row);
5448 if(this.CellSelection){
5449 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5452 if(this.RowSelection){
5453 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5457 sort : function(e,el)
5459 var col = Roo.get(el);
5461 if(!col.hasClass('sortable')){
5465 var sort = col.attr('sort');
5468 if(col.hasClass('glyphicon-arrow-up')){
5472 this.store.sortInfo = {field : sort, direction : dir};
5475 Roo.log("calling footer first");
5476 this.footer.onClick('first');
5479 this.store.load({ params : { start : 0 } });
5483 renderHeader : function()
5492 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5494 var config = cm.config[i];
5499 html: cm.getColumnHeader(i)
5502 if(typeof(config.tooltip) != 'undefined'){
5503 c.tooltip = config.tooltip;
5506 if(typeof(config.colspan) != 'undefined'){
5507 c.colspan = config.colspan;
5510 if(typeof(config.hidden) != 'undefined' && config.hidden){
5511 c.style += ' display:none;';
5514 if(typeof(config.dataIndex) != 'undefined'){
5515 c.sort = config.dataIndex;
5518 if(typeof(config.sortable) != 'undefined' && config.sortable){
5522 if(typeof(config.align) != 'undefined' && config.align.length){
5523 c.style += ' text-align:' + config.align + ';';
5526 if(typeof(config.width) != 'undefined'){
5527 c.style += ' width:' + config.width + 'px;';
5536 renderBody : function()
5546 colspan : this.cm.getColumnCount()
5556 renderFooter : function()
5566 colspan : this.cm.getColumnCount()
5580 Roo.log('ds onload');
5585 var ds = this.store;
5587 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5588 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5590 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5591 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5594 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5595 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5599 var tbody = this.mainBody;
5601 if(ds.getCount() > 0){
5602 ds.data.each(function(d,rowIndex){
5603 var row = this.renderRow(cm, ds, rowIndex);
5605 tbody.createChild(row);
5609 if(row.cellObjects.length){
5610 Roo.each(row.cellObjects, function(r){
5611 _this.renderCellObject(r);
5618 Roo.each(this.el.select('tbody td', true).elements, function(e){
5619 e.on('mouseover', _this.onMouseover, _this);
5622 Roo.each(this.el.select('tbody td', true).elements, function(e){
5623 e.on('mouseout', _this.onMouseout, _this);
5625 this.fireEvent('rowsrendered', this);
5626 //if(this.loadMask){
5627 // this.maskEl.hide();
5632 onUpdate : function(ds,record)
5634 this.refreshRow(record);
5637 onRemove : function(ds, record, index, isUpdate){
5638 if(isUpdate !== true){
5639 this.fireEvent("beforerowremoved", this, index, record);
5641 var bt = this.mainBody.dom;
5643 var rows = this.el.select('tbody > tr', true).elements;
5645 if(typeof(rows[index]) != 'undefined'){
5646 bt.removeChild(rows[index].dom);
5649 // if(bt.rows[index]){
5650 // bt.removeChild(bt.rows[index]);
5653 if(isUpdate !== true){
5654 //this.stripeRows(index);
5655 //this.syncRowHeights(index, index);
5657 this.fireEvent("rowremoved", this, index, record);
5661 onAdd : function(ds, records, rowIndex)
5663 //Roo.log('on Add called');
5664 // - note this does not handle multiple adding very well..
5665 var bt = this.mainBody.dom;
5666 for (var i =0 ; i < records.length;i++) {
5667 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5668 //Roo.log(records[i]);
5669 //Roo.log(this.store.getAt(rowIndex+i));
5670 this.insertRow(this.store, rowIndex + i, false);
5677 refreshRow : function(record){
5678 var ds = this.store, index;
5679 if(typeof record == 'number'){
5681 record = ds.getAt(index);
5683 index = ds.indexOf(record);
5685 this.insertRow(ds, index, true);
5686 this.onRemove(ds, record, index+1, true);
5687 //this.syncRowHeights(index, index);
5689 this.fireEvent("rowupdated", this, index, record);
5692 insertRow : function(dm, rowIndex, isUpdate){
5695 this.fireEvent("beforerowsinserted", this, rowIndex);
5697 //var s = this.getScrollState();
5698 var row = this.renderRow(this.cm, this.store, rowIndex);
5699 // insert before rowIndex..
5700 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5704 if(row.cellObjects.length){
5705 Roo.each(row.cellObjects, function(r){
5706 _this.renderCellObject(r);
5711 this.fireEvent("rowsinserted", this, rowIndex);
5712 //this.syncRowHeights(firstRow, lastRow);
5713 //this.stripeRows(firstRow);
5720 getRowDom : function(rowIndex)
5722 var rows = this.el.select('tbody > tr', true).elements;
5724 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5727 // returns the object tree for a tr..
5730 renderRow : function(cm, ds, rowIndex)
5733 var d = ds.getAt(rowIndex);
5740 var cellObjects = [];
5742 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5743 var config = cm.config[i];
5745 var renderer = cm.getRenderer(i);
5749 if(typeof(renderer) !== 'undefined'){
5750 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5752 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5753 // and are rendered into the cells after the row is rendered - using the id for the element.
5755 if(typeof(value) === 'object'){
5765 rowIndex : rowIndex,
5770 this.fireEvent('rowclass', this, rowcfg);
5774 cls : rowcfg.rowClass,
5776 html: (typeof(value) === 'object') ? '' : value
5783 if(typeof(config.colspan) != 'undefined'){
5784 td.colspan = config.colspan;
5787 if(typeof(config.hidden) != 'undefined' && config.hidden){
5788 td.style += ' display:none;';
5791 if(typeof(config.align) != 'undefined' && config.align.length){
5792 td.style += ' text-align:' + config.align + ';';
5795 if(typeof(config.width) != 'undefined'){
5796 td.style += ' width:' + config.width + 'px;';
5799 if(typeof(config.cursor) != 'undefined'){
5800 td.style += ' cursor:' + config.cursor + ';';
5807 row.cellObjects = cellObjects;
5815 onBeforeLoad : function()
5817 //Roo.log('ds onBeforeLoad');
5821 //if(this.loadMask){
5822 // this.maskEl.show();
5830 this.el.select('tbody', true).first().dom.innerHTML = '';
5833 * Show or hide a row.
5834 * @param {Number} rowIndex to show or hide
5835 * @param {Boolean} state hide
5837 setRowVisibility : function(rowIndex, state)
5839 var bt = this.mainBody.dom;
5841 var rows = this.el.select('tbody > tr', true).elements;
5843 if(typeof(rows[rowIndex]) == 'undefined'){
5846 rows[rowIndex].dom.style.display = state ? '' : 'none';
5850 getSelectionModel : function(){
5852 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5854 return this.selModel;
5857 * Render the Roo.bootstrap object from renderder
5859 renderCellObject : function(r)
5863 var t = r.cfg.render(r.container);
5866 Roo.each(r.cfg.cn, function(c){
5868 container: t.getChildContainer(),
5871 _this.renderCellObject(child);
5876 getRowIndex : function(row)
5880 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5903 * @class Roo.bootstrap.TableCell
5904 * @extends Roo.bootstrap.Component
5905 * Bootstrap TableCell class
5906 * @cfg {String} html cell contain text
5907 * @cfg {String} cls cell class
5908 * @cfg {String} tag cell tag (td|th) default td
5909 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5910 * @cfg {String} align Aligns the content in a cell
5911 * @cfg {String} axis Categorizes cells
5912 * @cfg {String} bgcolor Specifies the background color of a cell
5913 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5914 * @cfg {Number} colspan Specifies the number of columns a cell should span
5915 * @cfg {String} headers Specifies one or more header cells a cell is related to
5916 * @cfg {Number} height Sets the height of a cell
5917 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5918 * @cfg {Number} rowspan Sets the number of rows a cell should span
5919 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5920 * @cfg {String} valign Vertical aligns the content in a cell
5921 * @cfg {Number} width Specifies the width of a cell
5924 * Create a new TableCell
5925 * @param {Object} config The config object
5928 Roo.bootstrap.TableCell = function(config){
5929 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5932 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5952 getAutoCreate : function(){
5953 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5973 cfg.align=this.align
5979 cfg.bgcolor=this.bgcolor
5982 cfg.charoff=this.charoff
5985 cfg.colspan=this.colspan
5988 cfg.headers=this.headers
5991 cfg.height=this.height
5994 cfg.nowrap=this.nowrap
5997 cfg.rowspan=this.rowspan
6000 cfg.scope=this.scope
6003 cfg.valign=this.valign
6006 cfg.width=this.width
6025 * @class Roo.bootstrap.TableRow
6026 * @extends Roo.bootstrap.Component
6027 * Bootstrap TableRow class
6028 * @cfg {String} cls row class
6029 * @cfg {String} align Aligns the content in a table row
6030 * @cfg {String} bgcolor Specifies a background color for a table row
6031 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6032 * @cfg {String} valign Vertical aligns the content in a table row
6035 * Create a new TableRow
6036 * @param {Object} config The config object
6039 Roo.bootstrap.TableRow = function(config){
6040 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6043 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6051 getAutoCreate : function(){
6052 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6062 cfg.align = this.align;
6065 cfg.bgcolor = this.bgcolor;
6068 cfg.charoff = this.charoff;
6071 cfg.valign = this.valign;
6089 * @class Roo.bootstrap.TableBody
6090 * @extends Roo.bootstrap.Component
6091 * Bootstrap TableBody class
6092 * @cfg {String} cls element class
6093 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6094 * @cfg {String} align Aligns the content inside the element
6095 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6096 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6099 * Create a new TableBody
6100 * @param {Object} config The config object
6103 Roo.bootstrap.TableBody = function(config){
6104 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6107 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6115 getAutoCreate : function(){
6116 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6130 cfg.align = this.align;
6133 cfg.charoff = this.charoff;
6136 cfg.valign = this.valign;
6143 // initEvents : function()
6150 // this.store = Roo.factory(this.store, Roo.data);
6151 // this.store.on('load', this.onLoad, this);
6153 // this.store.load();
6157 // onLoad: function ()
6159 // this.fireEvent('load', this);
6169 * Ext JS Library 1.1.1
6170 * Copyright(c) 2006-2007, Ext JS, LLC.
6172 * Originally Released Under LGPL - original licence link has changed is not relivant.
6175 * <script type="text/javascript">
6178 // as we use this in bootstrap.
6179 Roo.namespace('Roo.form');
6181 * @class Roo.form.Action
6182 * Internal Class used to handle form actions
6184 * @param {Roo.form.BasicForm} el The form element or its id
6185 * @param {Object} config Configuration options
6190 // define the action interface
6191 Roo.form.Action = function(form, options){
6193 this.options = options || {};
6196 * Client Validation Failed
6199 Roo.form.Action.CLIENT_INVALID = 'client';
6201 * Server Validation Failed
6204 Roo.form.Action.SERVER_INVALID = 'server';
6206 * Connect to Server Failed
6209 Roo.form.Action.CONNECT_FAILURE = 'connect';
6211 * Reading Data from Server Failed
6214 Roo.form.Action.LOAD_FAILURE = 'load';
6216 Roo.form.Action.prototype = {
6218 failureType : undefined,
6219 response : undefined,
6223 run : function(options){
6228 success : function(response){
6233 handleResponse : function(response){
6237 // default connection failure
6238 failure : function(response){
6240 this.response = response;
6241 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6242 this.form.afterAction(this, false);
6245 processResponse : function(response){
6246 this.response = response;
6247 if(!response.responseText){
6250 this.result = this.handleResponse(response);
6254 // utility functions used internally
6255 getUrl : function(appendParams){
6256 var url = this.options.url || this.form.url || this.form.el.dom.action;
6258 var p = this.getParams();
6260 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6266 getMethod : function(){
6267 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6270 getParams : function(){
6271 var bp = this.form.baseParams;
6272 var p = this.options.params;
6274 if(typeof p == "object"){
6275 p = Roo.urlEncode(Roo.applyIf(p, bp));
6276 }else if(typeof p == 'string' && bp){
6277 p += '&' + Roo.urlEncode(bp);
6280 p = Roo.urlEncode(bp);
6285 createCallback : function(){
6287 success: this.success,
6288 failure: this.failure,
6290 timeout: (this.form.timeout*1000),
6291 upload: this.form.fileUpload ? this.success : undefined
6296 Roo.form.Action.Submit = function(form, options){
6297 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6300 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6303 haveProgress : false,
6304 uploadComplete : false,
6306 // uploadProgress indicator.
6307 uploadProgress : function()
6309 if (!this.form.progressUrl) {
6313 if (!this.haveProgress) {
6314 Roo.MessageBox.progress("Uploading", "Uploading");
6316 if (this.uploadComplete) {
6317 Roo.MessageBox.hide();
6321 this.haveProgress = true;
6323 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6325 var c = new Roo.data.Connection();
6327 url : this.form.progressUrl,
6332 success : function(req){
6333 //console.log(data);
6337 rdata = Roo.decode(req.responseText)
6339 Roo.log("Invalid data from server..");
6343 if (!rdata || !rdata.success) {
6345 Roo.MessageBox.alert(Roo.encode(rdata));
6348 var data = rdata.data;
6350 if (this.uploadComplete) {
6351 Roo.MessageBox.hide();
6356 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6357 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6360 this.uploadProgress.defer(2000,this);
6363 failure: function(data) {
6364 Roo.log('progress url failed ');
6375 // run get Values on the form, so it syncs any secondary forms.
6376 this.form.getValues();
6378 var o = this.options;
6379 var method = this.getMethod();
6380 var isPost = method == 'POST';
6381 if(o.clientValidation === false || this.form.isValid()){
6383 if (this.form.progressUrl) {
6384 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6385 (new Date() * 1) + '' + Math.random());
6390 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6391 form:this.form.el.dom,
6392 url:this.getUrl(!isPost),
6394 params:isPost ? this.getParams() : null,
6395 isUpload: this.form.fileUpload
6398 this.uploadProgress();
6400 }else if (o.clientValidation !== false){ // client validation failed
6401 this.failureType = Roo.form.Action.CLIENT_INVALID;
6402 this.form.afterAction(this, false);
6406 success : function(response)
6408 this.uploadComplete= true;
6409 if (this.haveProgress) {
6410 Roo.MessageBox.hide();
6414 var result = this.processResponse(response);
6415 if(result === true || result.success){
6416 this.form.afterAction(this, true);
6420 this.form.markInvalid(result.errors);
6421 this.failureType = Roo.form.Action.SERVER_INVALID;
6423 this.form.afterAction(this, false);
6425 failure : function(response)
6427 this.uploadComplete= true;
6428 if (this.haveProgress) {
6429 Roo.MessageBox.hide();
6432 this.response = response;
6433 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6434 this.form.afterAction(this, false);
6437 handleResponse : function(response){
6438 if(this.form.errorReader){
6439 var rs = this.form.errorReader.read(response);
6442 for(var i = 0, len = rs.records.length; i < len; i++) {
6443 var r = rs.records[i];
6447 if(errors.length < 1){
6451 success : rs.success,
6457 ret = Roo.decode(response.responseText);
6461 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6471 Roo.form.Action.Load = function(form, options){
6472 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6473 this.reader = this.form.reader;
6476 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6481 Roo.Ajax.request(Roo.apply(
6482 this.createCallback(), {
6483 method:this.getMethod(),
6484 url:this.getUrl(false),
6485 params:this.getParams()
6489 success : function(response){
6491 var result = this.processResponse(response);
6492 if(result === true || !result.success || !result.data){
6493 this.failureType = Roo.form.Action.LOAD_FAILURE;
6494 this.form.afterAction(this, false);
6497 this.form.clearInvalid();
6498 this.form.setValues(result.data);
6499 this.form.afterAction(this, true);
6502 handleResponse : function(response){
6503 if(this.form.reader){
6504 var rs = this.form.reader.read(response);
6505 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6507 success : rs.success,
6511 return Roo.decode(response.responseText);
6515 Roo.form.Action.ACTION_TYPES = {
6516 'load' : Roo.form.Action.Load,
6517 'submit' : Roo.form.Action.Submit
6526 * @class Roo.bootstrap.Form
6527 * @extends Roo.bootstrap.Component
6528 * Bootstrap Form class
6529 * @cfg {String} method GET | POST (default POST)
6530 * @cfg {String} labelAlign top | left (default top)
6531 * @cfg {String} align left | right - for navbars
6532 * @cfg {Boolean} loadMask load mask when submit (default true)
6537 * @param {Object} config The config object
6541 Roo.bootstrap.Form = function(config){
6542 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6545 * @event clientvalidation
6546 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6547 * @param {Form} this
6548 * @param {Boolean} valid true if the form has passed client-side validation
6550 clientvalidation: true,
6552 * @event beforeaction
6553 * Fires before any action is performed. Return false to cancel the action.
6554 * @param {Form} this
6555 * @param {Action} action The action to be performed
6559 * @event actionfailed
6560 * Fires when an action fails.
6561 * @param {Form} this
6562 * @param {Action} action The action that failed
6564 actionfailed : true,
6566 * @event actioncomplete
6567 * Fires when an action is completed.
6568 * @param {Form} this
6569 * @param {Action} action The action that completed
6571 actioncomplete : true
6576 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6579 * @cfg {String} method
6580 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6585 * The URL to use for form actions if one isn't supplied in the action options.
6588 * @cfg {Boolean} fileUpload
6589 * Set to true if this form is a file upload.
6593 * @cfg {Object} baseParams
6594 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6598 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6602 * @cfg {Sting} align (left|right) for navbar forms
6607 activeAction : null,
6610 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6611 * element by passing it or its id or mask the form itself by passing in true.
6614 waitMsgTarget : false,
6618 getAutoCreate : function(){
6622 method : this.method || 'POST',
6623 id : this.id || Roo.id(),
6626 if (this.parent().xtype.match(/^Nav/)) {
6627 cfg.cls = 'navbar-form navbar-' + this.align;
6631 if (this.labelAlign == 'left' ) {
6632 cfg.cls += ' form-horizontal';
6638 initEvents : function()
6640 this.el.on('submit', this.onSubmit, this);
6641 // this was added as random key presses on the form where triggering form submit.
6642 this.el.on('keypress', function(e) {
6643 if (e.getCharCode() != 13) {
6646 // we might need to allow it for textareas.. and some other items.
6647 // check e.getTarget().
6649 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6653 Roo.log("keypress blocked");
6661 onSubmit : function(e){
6666 * Returns true if client-side validation on the form is successful.
6669 isValid : function(){
6670 var items = this.getItems();
6672 items.each(function(f){
6681 * Returns true if any fields in this form have changed since their original load.
6684 isDirty : function(){
6686 var items = this.getItems();
6687 items.each(function(f){
6697 * Performs a predefined action (submit or load) or custom actions you define on this form.
6698 * @param {String} actionName The name of the action type
6699 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6700 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6701 * accept other config options):
6703 Property Type Description
6704 ---------------- --------------- ----------------------------------------------------------------------------------
6705 url String The url for the action (defaults to the form's url)
6706 method String The form method to use (defaults to the form's method, or POST if not defined)
6707 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6708 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6709 validate the form on the client (defaults to false)
6711 * @return {BasicForm} this
6713 doAction : function(action, options){
6714 if(typeof action == 'string'){
6715 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6717 if(this.fireEvent('beforeaction', this, action) !== false){
6718 this.beforeAction(action);
6719 action.run.defer(100, action);
6725 beforeAction : function(action){
6726 var o = action.options;
6729 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6731 // not really supported yet.. ??
6733 //if(this.waitMsgTarget === true){
6734 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6735 //}else if(this.waitMsgTarget){
6736 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6737 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6739 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6745 afterAction : function(action, success){
6746 this.activeAction = null;
6747 var o = action.options;
6749 //if(this.waitMsgTarget === true){
6751 //}else if(this.waitMsgTarget){
6752 // this.waitMsgTarget.unmask();
6754 // Roo.MessageBox.updateProgress(1);
6755 // Roo.MessageBox.hide();
6762 Roo.callback(o.success, o.scope, [this, action]);
6763 this.fireEvent('actioncomplete', this, action);
6767 // failure condition..
6768 // we have a scenario where updates need confirming.
6769 // eg. if a locking scenario exists..
6770 // we look for { errors : { needs_confirm : true }} in the response.
6772 (typeof(action.result) != 'undefined') &&
6773 (typeof(action.result.errors) != 'undefined') &&
6774 (typeof(action.result.errors.needs_confirm) != 'undefined')
6777 Roo.log("not supported yet");
6780 Roo.MessageBox.confirm(
6781 "Change requires confirmation",
6782 action.result.errorMsg,
6787 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6797 Roo.callback(o.failure, o.scope, [this, action]);
6798 // show an error message if no failed handler is set..
6799 if (!this.hasListener('actionfailed')) {
6800 Roo.log("need to add dialog support");
6802 Roo.MessageBox.alert("Error",
6803 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6804 action.result.errorMsg :
6805 "Saving Failed, please check your entries or try again"
6810 this.fireEvent('actionfailed', this, action);
6815 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6816 * @param {String} id The value to search for
6819 findField : function(id){
6820 var items = this.getItems();
6821 var field = items.get(id);
6823 items.each(function(f){
6824 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6831 return field || null;
6834 * Mark fields in this form invalid in bulk.
6835 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6836 * @return {BasicForm} this
6838 markInvalid : function(errors){
6839 if(errors instanceof Array){
6840 for(var i = 0, len = errors.length; i < len; i++){
6841 var fieldError = errors[i];
6842 var f = this.findField(fieldError.id);
6844 f.markInvalid(fieldError.msg);
6850 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6851 field.markInvalid(errors[id]);
6855 //Roo.each(this.childForms || [], function (f) {
6856 // f.markInvalid(errors);
6863 * Set values for fields in this form in bulk.
6864 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6865 * @return {BasicForm} this
6867 setValues : function(values){
6868 if(values instanceof Array){ // array of objects
6869 for(var i = 0, len = values.length; i < len; i++){
6871 var f = this.findField(v.id);
6873 f.setValue(v.value);
6874 if(this.trackResetOnLoad){
6875 f.originalValue = f.getValue();
6879 }else{ // object hash
6882 if(typeof values[id] != 'function' && (field = this.findField(id))){
6884 if (field.setFromData &&
6886 field.displayField &&
6887 // combos' with local stores can
6888 // be queried via setValue()
6889 // to set their value..
6890 (field.store && !field.store.isLocal)
6894 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6895 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6896 field.setFromData(sd);
6899 field.setValue(values[id]);
6903 if(this.trackResetOnLoad){
6904 field.originalValue = field.getValue();
6910 //Roo.each(this.childForms || [], function (f) {
6911 // f.setValues(values);
6918 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6919 * they are returned as an array.
6920 * @param {Boolean} asString
6923 getValues : function(asString){
6924 //if (this.childForms) {
6925 // copy values from the child forms
6926 // Roo.each(this.childForms, function (f) {
6927 // this.setValues(f.getValues());
6933 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6934 if(asString === true){
6937 return Roo.urlDecode(fs);
6941 * Returns the fields in this form as an object with key/value pairs.
6942 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6945 getFieldValues : function(with_hidden)
6947 var items = this.getItems();
6949 items.each(function(f){
6953 var v = f.getValue();
6954 if (f.inputType =='radio') {
6955 if (typeof(ret[f.getName()]) == 'undefined') {
6956 ret[f.getName()] = ''; // empty..
6959 if (!f.el.dom.checked) {
6967 // not sure if this supported any more..
6968 if ((typeof(v) == 'object') && f.getRawValue) {
6969 v = f.getRawValue() ; // dates..
6971 // combo boxes where name != hiddenName...
6972 if (f.name != f.getName()) {
6973 ret[f.name] = f.getRawValue();
6975 ret[f.getName()] = v;
6982 * Clears all invalid messages in this form.
6983 * @return {BasicForm} this
6985 clearInvalid : function(){
6986 var items = this.getItems();
6988 items.each(function(f){
6999 * @return {BasicForm} this
7002 var items = this.getItems();
7003 items.each(function(f){
7007 Roo.each(this.childForms || [], function (f) {
7014 getItems : function()
7016 var r=new Roo.util.MixedCollection(false, function(o){
7017 return o.id || (o.id = Roo.id());
7019 var iter = function(el) {
7026 Roo.each(el.items,function(e) {
7046 * Ext JS Library 1.1.1
7047 * Copyright(c) 2006-2007, Ext JS, LLC.
7049 * Originally Released Under LGPL - original licence link has changed is not relivant.
7052 * <script type="text/javascript">
7055 * @class Roo.form.VTypes
7056 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7059 Roo.form.VTypes = function(){
7060 // closure these in so they are only created once.
7061 var alpha = /^[a-zA-Z_]+$/;
7062 var alphanum = /^[a-zA-Z0-9_]+$/;
7063 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7064 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7066 // All these messages and functions are configurable
7069 * The function used to validate email addresses
7070 * @param {String} value The email address
7072 'email' : function(v){
7073 return email.test(v);
7076 * The error text to display when the email validation function returns false
7079 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7081 * The keystroke filter mask to be applied on email input
7084 'emailMask' : /[a-z0-9_\.\-@]/i,
7087 * The function used to validate URLs
7088 * @param {String} value The URL
7090 'url' : function(v){
7094 * The error text to display when the url validation function returns false
7097 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7100 * The function used to validate alpha values
7101 * @param {String} value The value
7103 'alpha' : function(v){
7104 return alpha.test(v);
7107 * The error text to display when the alpha validation function returns false
7110 'alphaText' : 'This field should only contain letters and _',
7112 * The keystroke filter mask to be applied on alpha input
7115 'alphaMask' : /[a-z_]/i,
7118 * The function used to validate alphanumeric values
7119 * @param {String} value The value
7121 'alphanum' : function(v){
7122 return alphanum.test(v);
7125 * The error text to display when the alphanumeric validation function returns false
7128 'alphanumText' : 'This field should only contain letters, numbers and _',
7130 * The keystroke filter mask to be applied on alphanumeric input
7133 'alphanumMask' : /[a-z0-9_]/i
7143 * @class Roo.bootstrap.Input
7144 * @extends Roo.bootstrap.Component
7145 * Bootstrap Input class
7146 * @cfg {Boolean} disabled is it disabled
7147 * @cfg {String} fieldLabel - the label associated
7148 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7149 * @cfg {String} name name of the input
7150 * @cfg {string} fieldLabel - the label associated
7151 * @cfg {string} inputType - input / file submit ...
7152 * @cfg {string} placeholder - placeholder to put in text.
7153 * @cfg {string} before - input group add on before
7154 * @cfg {string} after - input group add on after
7155 * @cfg {string} size - (lg|sm) or leave empty..
7156 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7157 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7158 * @cfg {Number} md colspan out of 12 for computer-sized screens
7159 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7160 * @cfg {string} value default value of the input
7161 * @cfg {Number} labelWidth set the width of label (0-12)
7162 * @cfg {String} labelAlign (top|left)
7163 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7164 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7166 * @cfg {String} align (left|center|right) Default left
7171 * Create a new Input
7172 * @param {Object} config The config object
7175 Roo.bootstrap.Input = function(config){
7176 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7181 * Fires when this field receives input focus.
7182 * @param {Roo.form.Field} this
7187 * Fires when this field loses input focus.
7188 * @param {Roo.form.Field} this
7193 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7194 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7195 * @param {Roo.form.Field} this
7196 * @param {Roo.EventObject} e The event object
7201 * Fires just before the field blurs if the field value has changed.
7202 * @param {Roo.form.Field} this
7203 * @param {Mixed} newValue The new value
7204 * @param {Mixed} oldValue The original value
7209 * Fires after the field has been marked as invalid.
7210 * @param {Roo.form.Field} this
7211 * @param {String} msg The validation message
7216 * Fires after the field has been validated with no errors.
7217 * @param {Roo.form.Field} this
7222 * Fires after the key up
7223 * @param {Roo.form.Field} this
7224 * @param {Roo.EventObject} e The event Object
7230 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7232 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7233 automatic validation (defaults to "keyup").
7235 validationEvent : "keyup",
7237 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7239 validateOnBlur : true,
7241 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7243 validationDelay : 250,
7245 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7247 focusClass : "x-form-focus", // not needed???
7251 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7253 invalidClass : "has-warning",
7256 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7258 validClass : "has-success",
7261 * @cfg {Boolean} hasFeedback (true|false) default true
7266 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7268 invalidFeedbackClass : "glyphicon-warning-sign",
7271 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7273 validFeedbackClass : "glyphicon-ok",
7276 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7278 selectOnFocus : false,
7281 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7285 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7290 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7292 disableKeyFilter : false,
7295 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7299 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7303 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7305 blankText : "This field is required",
7308 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7312 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7314 maxLength : Number.MAX_VALUE,
7316 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7318 minLengthText : "The minimum length for this field is {0}",
7320 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7322 maxLengthText : "The maximum length for this field is {0}",
7326 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7327 * If available, this function will be called only after the basic validators all return true, and will be passed the
7328 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7332 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7333 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7334 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7338 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7342 autocomplete: false,
7361 formatedValue : false,
7363 parentLabelAlign : function()
7366 while (parent.parent()) {
7367 parent = parent.parent();
7368 if (typeof(parent.labelAlign) !='undefined') {
7369 return parent.labelAlign;
7376 getAutoCreate : function(){
7378 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7384 if(this.inputType != 'hidden'){
7385 cfg.cls = 'form-group' //input-group
7391 type : this.inputType,
7393 cls : 'form-control',
7394 placeholder : this.placeholder || '',
7395 autocomplete : this.autocomplete || 'new-password'
7400 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7403 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7404 input.maxLength = this.maxLength;
7407 if (this.disabled) {
7408 input.disabled=true;
7411 if (this.readOnly) {
7412 input.readonly=true;
7416 input.name = this.name;
7419 input.cls += ' input-' + this.size;
7422 ['xs','sm','md','lg'].map(function(size){
7423 if (settings[size]) {
7424 cfg.cls += ' col-' + size + '-' + settings[size];
7428 var inputblock = input;
7430 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7434 cls: 'glyphicon form-control-feedback'
7438 cls : 'has-feedback',
7446 // var inputblock = input;
7448 if (this.before || this.after) {
7451 cls : 'input-group',
7455 if (this.before && typeof(this.before) == 'string') {
7457 inputblock.cn.push({
7459 cls : 'roo-input-before input-group-addon',
7463 if (this.before && typeof(this.before) == 'object') {
7464 this.before = Roo.factory(this.before);
7465 Roo.log(this.before);
7466 inputblock.cn.push({
7468 cls : 'roo-input-before input-group-' +
7469 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7473 inputblock.cn.push(input);
7475 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7476 inputblock.cls += ' has-feedback';
7477 inputblock.cn.push(feedback);
7480 if (this.after && typeof(this.after) == 'string') {
7481 inputblock.cn.push({
7483 cls : 'roo-input-after input-group-addon',
7487 if (this.after && typeof(this.after) == 'object') {
7488 this.after = Roo.factory(this.after);
7489 Roo.log(this.after);
7490 inputblock.cn.push({
7492 cls : 'roo-input-after input-group-' +
7493 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7498 if (align ==='left' && this.fieldLabel.length) {
7499 Roo.log("left and has label");
7505 cls : 'control-label col-sm-' + this.labelWidth,
7506 html : this.fieldLabel
7510 cls : "col-sm-" + (12 - this.labelWidth),
7517 } else if ( this.fieldLabel.length) {
7523 //cls : 'input-group-addon',
7524 html : this.fieldLabel
7534 Roo.log(" no label && no align");
7543 Roo.log('input-parentType: ' + this.parentType);
7545 if (this.parentType === 'Navbar' && this.parent().bar) {
7546 cfg.cls += ' navbar-form';
7554 * return the real input element.
7556 inputEl: function ()
7558 return this.el.select('input.form-control',true).first();
7561 tooltipEl : function()
7563 return this.inputEl();
7566 setDisabled : function(v)
7568 var i = this.inputEl().dom;
7570 i.removeAttribute('disabled');
7574 i.setAttribute('disabled','true');
7576 initEvents : function()
7579 this.inputEl().on("keydown" , this.fireKey, this);
7580 this.inputEl().on("focus", this.onFocus, this);
7581 this.inputEl().on("blur", this.onBlur, this);
7583 this.inputEl().relayEvent('keyup', this);
7585 // reference to original value for reset
7586 this.originalValue = this.getValue();
7587 //Roo.form.TextField.superclass.initEvents.call(this);
7588 if(this.validationEvent == 'keyup'){
7589 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7590 this.inputEl().on('keyup', this.filterValidation, this);
7592 else if(this.validationEvent !== false){
7593 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7596 if(this.selectOnFocus){
7597 this.on("focus", this.preFocus, this);
7600 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7601 this.inputEl().on("keypress", this.filterKeys, this);
7604 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7605 this.el.on("click", this.autoSize, this);
7608 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7609 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7612 if (typeof(this.before) == 'object') {
7613 this.before.render(this.el.select('.roo-input-before',true).first());
7615 if (typeof(this.after) == 'object') {
7616 this.after.render(this.el.select('.roo-input-after',true).first());
7621 filterValidation : function(e){
7622 if(!e.isNavKeyPress()){
7623 this.validationTask.delay(this.validationDelay);
7627 * Validates the field value
7628 * @return {Boolean} True if the value is valid, else false
7630 validate : function(){
7631 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7632 if(this.disabled || this.validateValue(this.getRawValue())){
7643 * Validates a value according to the field's validation rules and marks the field as invalid
7644 * if the validation fails
7645 * @param {Mixed} value The value to validate
7646 * @return {Boolean} True if the value is valid, else false
7648 validateValue : function(value){
7649 if(value.length < 1) { // if it's blank
7650 if(this.allowBlank){
7656 if(value.length < this.minLength){
7659 if(value.length > this.maxLength){
7663 var vt = Roo.form.VTypes;
7664 if(!vt[this.vtype](value, this)){
7668 if(typeof this.validator == "function"){
7669 var msg = this.validator(value);
7675 if(this.regex && !this.regex.test(value)){
7685 fireKey : function(e){
7686 //Roo.log('field ' + e.getKey());
7687 if(e.isNavKeyPress()){
7688 this.fireEvent("specialkey", this, e);
7691 focus : function (selectText){
7693 this.inputEl().focus();
7694 if(selectText === true){
7695 this.inputEl().dom.select();
7701 onFocus : function(){
7702 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7703 // this.el.addClass(this.focusClass);
7706 this.hasFocus = true;
7707 this.startValue = this.getValue();
7708 this.fireEvent("focus", this);
7712 beforeBlur : Roo.emptyFn,
7716 onBlur : function(){
7718 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7719 //this.el.removeClass(this.focusClass);
7721 this.hasFocus = false;
7722 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7725 var v = this.getValue();
7726 if(String(v) !== String(this.startValue)){
7727 this.fireEvent('change', this, v, this.startValue);
7729 this.fireEvent("blur", this);
7733 * Resets the current field value to the originally loaded value and clears any validation messages
7736 this.setValue(this.originalValue);
7740 * Returns the name of the field
7741 * @return {Mixed} name The name field
7743 getName: function(){
7747 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7748 * @return {Mixed} value The field value
7750 getValue : function(){
7752 var v = this.inputEl().getValue();
7757 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7758 * @return {Mixed} value The field value
7760 getRawValue : function(){
7761 var v = this.inputEl().getValue();
7767 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7768 * @param {Mixed} value The value to set
7770 setRawValue : function(v){
7771 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7774 selectText : function(start, end){
7775 var v = this.getRawValue();
7777 start = start === undefined ? 0 : start;
7778 end = end === undefined ? v.length : end;
7779 var d = this.inputEl().dom;
7780 if(d.setSelectionRange){
7781 d.setSelectionRange(start, end);
7782 }else if(d.createTextRange){
7783 var range = d.createTextRange();
7784 range.moveStart("character", start);
7785 range.moveEnd("character", v.length-end);
7792 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7793 * @param {Mixed} value The value to set
7795 setValue : function(v){
7798 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7804 processValue : function(value){
7805 if(this.stripCharsRe){
7806 var newValue = value.replace(this.stripCharsRe, '');
7807 if(newValue !== value){
7808 this.setRawValue(newValue);
7815 preFocus : function(){
7817 if(this.selectOnFocus){
7818 this.inputEl().dom.select();
7821 filterKeys : function(e){
7823 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7826 var c = e.getCharCode(), cc = String.fromCharCode(c);
7827 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7830 if(!this.maskRe.test(cc)){
7835 * Clear any invalid styles/messages for this field
7837 clearInvalid : function(){
7839 if(!this.el || this.preventMark){ // not rendered
7842 this.el.removeClass(this.invalidClass);
7844 this.fireEvent('valid', this);
7848 * Mark this field as valid
7850 markValid : function(){
7851 if(!this.el || this.preventMark){ // not rendered
7855 this.el.removeClass([this.invalidClass, this.validClass]);
7857 if(this.disabled || this.allowBlank){
7861 this.el.addClass(this.validClass);
7863 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7865 var feedback = this.el.select('.form-control-feedback', true).first();
7868 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7869 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7874 this.fireEvent('valid', this);
7878 * Mark this field as invalid
7879 * @param {String} msg The validation message
7881 markInvalid : function(msg){
7882 if(!this.el || this.preventMark){ // not rendered
7886 this.el.removeClass([this.invalidClass, this.validClass]);
7888 if(this.disabled || this.allowBlank){
7892 this.el.addClass(this.invalidClass);
7894 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7896 var feedback = this.el.select('.form-control-feedback', true).first();
7899 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7901 if(this.getValue().length){
7902 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7909 this.fireEvent('invalid', this, msg);
7912 SafariOnKeyDown : function(event)
7914 // this is a workaround for a password hang bug on chrome/ webkit.
7916 var isSelectAll = false;
7918 if(this.inputEl().dom.selectionEnd > 0){
7919 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7921 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7922 event.preventDefault();
7927 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7929 event.preventDefault();
7930 // this is very hacky as keydown always get's upper case.
7932 var cc = String.fromCharCode(event.getCharCode());
7933 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7937 adjustWidth : function(tag, w){
7938 tag = tag.toLowerCase();
7939 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7940 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7944 if(tag == 'textarea'){
7947 }else if(Roo.isOpera){
7951 if(tag == 'textarea'){
7970 * @class Roo.bootstrap.TextArea
7971 * @extends Roo.bootstrap.Input
7972 * Bootstrap TextArea class
7973 * @cfg {Number} cols Specifies the visible width of a text area
7974 * @cfg {Number} rows Specifies the visible number of lines in a text area
7975 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7976 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7977 * @cfg {string} html text
7980 * Create a new TextArea
7981 * @param {Object} config The config object
7984 Roo.bootstrap.TextArea = function(config){
7985 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7989 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7999 getAutoCreate : function(){
8001 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8012 value : this.value || '',
8013 html: this.html || '',
8014 cls : 'form-control',
8015 placeholder : this.placeholder || ''
8019 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8020 input.maxLength = this.maxLength;
8024 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8028 input.cols = this.cols;
8031 if (this.readOnly) {
8032 input.readonly = true;
8036 input.name = this.name;
8040 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8044 ['xs','sm','md','lg'].map(function(size){
8045 if (settings[size]) {
8046 cfg.cls += ' col-' + size + '-' + settings[size];
8050 var inputblock = input;
8052 if(this.hasFeedback && !this.allowBlank){
8056 cls: 'glyphicon form-control-feedback'
8060 cls : 'has-feedback',
8069 if (this.before || this.after) {
8072 cls : 'input-group',
8076 inputblock.cn.push({
8078 cls : 'input-group-addon',
8083 inputblock.cn.push(input);
8085 if(this.hasFeedback && !this.allowBlank){
8086 inputblock.cls += ' has-feedback';
8087 inputblock.cn.push(feedback);
8091 inputblock.cn.push({
8093 cls : 'input-group-addon',
8100 if (align ==='left' && this.fieldLabel.length) {
8101 Roo.log("left and has label");
8107 cls : 'control-label col-sm-' + this.labelWidth,
8108 html : this.fieldLabel
8112 cls : "col-sm-" + (12 - this.labelWidth),
8119 } else if ( this.fieldLabel.length) {
8125 //cls : 'input-group-addon',
8126 html : this.fieldLabel
8136 Roo.log(" no label && no align");
8146 if (this.disabled) {
8147 input.disabled=true;
8154 * return the real textarea element.
8156 inputEl: function ()
8158 return this.el.select('textarea.form-control',true).first();
8166 * trigger field - base class for combo..
8171 * @class Roo.bootstrap.TriggerField
8172 * @extends Roo.bootstrap.Input
8173 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8174 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8175 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8176 * for which you can provide a custom implementation. For example:
8178 var trigger = new Roo.bootstrap.TriggerField();
8179 trigger.onTriggerClick = myTriggerFn;
8180 trigger.applyTo('my-field');
8183 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8184 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8185 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8186 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8187 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8190 * Create a new TriggerField.
8191 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8192 * to the base TextField)
8194 Roo.bootstrap.TriggerField = function(config){
8195 this.mimicing = false;
8196 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8199 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8201 * @cfg {String} triggerClass A CSS class to apply to the trigger
8204 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8208 /** @cfg {Boolean} grow @hide */
8209 /** @cfg {Number} growMin @hide */
8210 /** @cfg {Number} growMax @hide */
8216 autoSize: Roo.emptyFn,
8223 actionMode : 'wrap',
8228 getAutoCreate : function(){
8230 var align = this.labelAlign || this.parentLabelAlign();
8235 cls: 'form-group' //input-group
8242 type : this.inputType,
8243 cls : 'form-control',
8244 autocomplete: 'new-password',
8245 placeholder : this.placeholder || ''
8249 input.name = this.name;
8252 input.cls += ' input-' + this.size;
8255 if (this.disabled) {
8256 input.disabled=true;
8259 var inputblock = input;
8261 if(this.hasFeedback && !this.allowBlank){
8265 cls: 'glyphicon form-control-feedback'
8269 cls : 'has-feedback',
8277 if (this.before || this.after) {
8280 cls : 'input-group',
8284 inputblock.cn.push({
8286 cls : 'input-group-addon',
8291 inputblock.cn.push(input);
8293 if(this.hasFeedback && !this.allowBlank){
8294 inputblock.cls += ' has-feedback';
8295 inputblock.cn.push(feedback);
8299 inputblock.cn.push({
8301 cls : 'input-group-addon',
8314 cls: 'form-hidden-field'
8322 Roo.log('multiple');
8330 cls: 'form-hidden-field'
8334 cls: 'select2-choices',
8338 cls: 'select2-search-field',
8351 cls: 'select2-container input-group',
8356 // cls: 'typeahead typeahead-long dropdown-menu',
8357 // style: 'display:none'
8362 if(!this.multiple && this.showToggleBtn){
8368 if (this.caret != false) {
8371 cls: 'fa fa-' + this.caret
8378 cls : 'input-group-addon btn dropdown-toggle',
8383 cls: 'combobox-clear',
8397 combobox.cls += ' select2-container-multi';
8400 if (align ==='left' && this.fieldLabel.length) {
8402 Roo.log("left and has label");
8408 cls : 'control-label col-sm-' + this.labelWidth,
8409 html : this.fieldLabel
8413 cls : "col-sm-" + (12 - this.labelWidth),
8420 } else if ( this.fieldLabel.length) {
8426 //cls : 'input-group-addon',
8427 html : this.fieldLabel
8437 Roo.log(" no label && no align");
8444 ['xs','sm','md','lg'].map(function(size){
8445 if (settings[size]) {
8446 cfg.cls += ' col-' + size + '-' + settings[size];
8457 onResize : function(w, h){
8458 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8459 // if(typeof w == 'number'){
8460 // var x = w - this.trigger.getWidth();
8461 // this.inputEl().setWidth(this.adjustWidth('input', x));
8462 // this.trigger.setStyle('left', x+'px');
8467 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8470 getResizeEl : function(){
8471 return this.inputEl();
8475 getPositionEl : function(){
8476 return this.inputEl();
8480 alignErrorIcon : function(){
8481 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8485 initEvents : function(){
8489 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8490 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8491 if(!this.multiple && this.showToggleBtn){
8492 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8493 if(this.hideTrigger){
8494 this.trigger.setDisplayed(false);
8496 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8500 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8503 //this.trigger.addClassOnOver('x-form-trigger-over');
8504 //this.trigger.addClassOnClick('x-form-trigger-click');
8507 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8511 createList : function()
8513 this.list = Roo.get(document.body).createChild({
8515 cls: 'typeahead typeahead-long dropdown-menu',
8516 style: 'display:none'
8519 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8524 initTrigger : function(){
8529 onDestroy : function(){
8531 this.trigger.removeAllListeners();
8532 // this.trigger.remove();
8535 // this.wrap.remove();
8537 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8541 onFocus : function(){
8542 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8545 this.wrap.addClass('x-trigger-wrap-focus');
8546 this.mimicing = true;
8547 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8548 if(this.monitorTab){
8549 this.el.on("keydown", this.checkTab, this);
8556 checkTab : function(e){
8557 if(e.getKey() == e.TAB){
8563 onBlur : function(){
8568 mimicBlur : function(e, t){
8570 if(!this.wrap.contains(t) && this.validateBlur()){
8577 triggerBlur : function(){
8578 this.mimicing = false;
8579 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8580 if(this.monitorTab){
8581 this.el.un("keydown", this.checkTab, this);
8583 //this.wrap.removeClass('x-trigger-wrap-focus');
8584 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8588 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8589 validateBlur : function(e, t){
8594 onDisable : function(){
8595 this.inputEl().dom.disabled = true;
8596 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8598 // this.wrap.addClass('x-item-disabled');
8603 onEnable : function(){
8604 this.inputEl().dom.disabled = false;
8605 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8607 // this.el.removeClass('x-item-disabled');
8612 onShow : function(){
8613 var ae = this.getActionEl();
8616 ae.dom.style.display = '';
8617 ae.dom.style.visibility = 'visible';
8623 onHide : function(){
8624 var ae = this.getActionEl();
8625 ae.dom.style.display = 'none';
8629 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8630 * by an implementing function.
8632 * @param {EventObject} e
8634 onTriggerClick : Roo.emptyFn
8638 * Ext JS Library 1.1.1
8639 * Copyright(c) 2006-2007, Ext JS, LLC.
8641 * Originally Released Under LGPL - original licence link has changed is not relivant.
8644 * <script type="text/javascript">
8649 * @class Roo.data.SortTypes
8651 * Defines the default sorting (casting?) comparison functions used when sorting data.
8653 Roo.data.SortTypes = {
8655 * Default sort that does nothing
8656 * @param {Mixed} s The value being converted
8657 * @return {Mixed} The comparison value
8664 * The regular expression used to strip tags
8668 stripTagsRE : /<\/?[^>]+>/gi,
8671 * Strips all HTML tags to sort on text only
8672 * @param {Mixed} s The value being converted
8673 * @return {String} The comparison value
8675 asText : function(s){
8676 return String(s).replace(this.stripTagsRE, "");
8680 * Strips all HTML tags to sort on text only - Case insensitive
8681 * @param {Mixed} s The value being converted
8682 * @return {String} The comparison value
8684 asUCText : function(s){
8685 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8689 * Case insensitive string
8690 * @param {Mixed} s The value being converted
8691 * @return {String} The comparison value
8693 asUCString : function(s) {
8694 return String(s).toUpperCase();
8699 * @param {Mixed} s The value being converted
8700 * @return {Number} The comparison value
8702 asDate : function(s) {
8706 if(s instanceof Date){
8709 return Date.parse(String(s));
8714 * @param {Mixed} s The value being converted
8715 * @return {Float} The comparison value
8717 asFloat : function(s) {
8718 var val = parseFloat(String(s).replace(/,/g, ""));
8719 if(isNaN(val)) val = 0;
8725 * @param {Mixed} s The value being converted
8726 * @return {Number} The comparison value
8728 asInt : function(s) {
8729 var val = parseInt(String(s).replace(/,/g, ""));
8730 if(isNaN(val)) val = 0;
8735 * Ext JS Library 1.1.1
8736 * Copyright(c) 2006-2007, Ext JS, LLC.
8738 * Originally Released Under LGPL - original licence link has changed is not relivant.
8741 * <script type="text/javascript">
8745 * @class Roo.data.Record
8746 * Instances of this class encapsulate both record <em>definition</em> information, and record
8747 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8748 * to access Records cached in an {@link Roo.data.Store} object.<br>
8750 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8751 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8754 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8756 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8757 * {@link #create}. The parameters are the same.
8758 * @param {Array} data An associative Array of data values keyed by the field name.
8759 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8760 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8761 * not specified an integer id is generated.
8763 Roo.data.Record = function(data, id){
8764 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8769 * Generate a constructor for a specific record layout.
8770 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8771 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8772 * Each field definition object may contain the following properties: <ul>
8773 * <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,
8774 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8775 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8776 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8777 * is being used, then this is a string containing the javascript expression to reference the data relative to
8778 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8779 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8780 * this may be omitted.</p></li>
8781 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8782 * <ul><li>auto (Default, implies no conversion)</li>
8787 * <li>date</li></ul></p></li>
8788 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8789 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8790 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8791 * by the Reader into an object that will be stored in the Record. It is passed the
8792 * following parameters:<ul>
8793 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8795 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8797 * <br>usage:<br><pre><code>
8798 var TopicRecord = Roo.data.Record.create(
8799 {name: 'title', mapping: 'topic_title'},
8800 {name: 'author', mapping: 'username'},
8801 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8802 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8803 {name: 'lastPoster', mapping: 'user2'},
8804 {name: 'excerpt', mapping: 'post_text'}
8807 var myNewRecord = new TopicRecord({
8808 title: 'Do my job please',
8811 lastPost: new Date(),
8812 lastPoster: 'Animal',
8813 excerpt: 'No way dude!'
8815 myStore.add(myNewRecord);
8820 Roo.data.Record.create = function(o){
8822 f.superclass.constructor.apply(this, arguments);
8824 Roo.extend(f, Roo.data.Record);
8825 var p = f.prototype;
8826 p.fields = new Roo.util.MixedCollection(false, function(field){
8829 for(var i = 0, len = o.length; i < len; i++){
8830 p.fields.add(new Roo.data.Field(o[i]));
8832 f.getField = function(name){
8833 return p.fields.get(name);
8838 Roo.data.Record.AUTO_ID = 1000;
8839 Roo.data.Record.EDIT = 'edit';
8840 Roo.data.Record.REJECT = 'reject';
8841 Roo.data.Record.COMMIT = 'commit';
8843 Roo.data.Record.prototype = {
8845 * Readonly flag - true if this record has been modified.
8854 join : function(store){
8859 * Set the named field to the specified value.
8860 * @param {String} name The name of the field to set.
8861 * @param {Object} value The value to set the field to.
8863 set : function(name, value){
8864 if(this.data[name] == value){
8871 if(typeof this.modified[name] == 'undefined'){
8872 this.modified[name] = this.data[name];
8874 this.data[name] = value;
8875 if(!this.editing && this.store){
8876 this.store.afterEdit(this);
8881 * Get the value of the named field.
8882 * @param {String} name The name of the field to get the value of.
8883 * @return {Object} The value of the field.
8885 get : function(name){
8886 return this.data[name];
8890 beginEdit : function(){
8891 this.editing = true;
8896 cancelEdit : function(){
8897 this.editing = false;
8898 delete this.modified;
8902 endEdit : function(){
8903 this.editing = false;
8904 if(this.dirty && this.store){
8905 this.store.afterEdit(this);
8910 * Usually called by the {@link Roo.data.Store} which owns the Record.
8911 * Rejects all changes made to the Record since either creation, or the last commit operation.
8912 * Modified fields are reverted to their original values.
8914 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8915 * of reject operations.
8917 reject : function(){
8918 var m = this.modified;
8920 if(typeof m[n] != "function"){
8921 this.data[n] = m[n];
8925 delete this.modified;
8926 this.editing = false;
8928 this.store.afterReject(this);
8933 * Usually called by the {@link Roo.data.Store} which owns the Record.
8934 * Commits all changes made to the Record since either creation, or the last commit operation.
8936 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8937 * of commit operations.
8939 commit : function(){
8941 delete this.modified;
8942 this.editing = false;
8944 this.store.afterCommit(this);
8949 hasError : function(){
8950 return this.error != null;
8954 clearError : function(){
8959 * Creates a copy of this record.
8960 * @param {String} id (optional) A new record id if you don't want to use this record's id
8963 copy : function(newId) {
8964 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8968 * Ext JS Library 1.1.1
8969 * Copyright(c) 2006-2007, Ext JS, LLC.
8971 * Originally Released Under LGPL - original licence link has changed is not relivant.
8974 * <script type="text/javascript">
8980 * @class Roo.data.Store
8981 * @extends Roo.util.Observable
8982 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8983 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8985 * 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
8986 * has no knowledge of the format of the data returned by the Proxy.<br>
8988 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8989 * instances from the data object. These records are cached and made available through accessor functions.
8991 * Creates a new Store.
8992 * @param {Object} config A config object containing the objects needed for the Store to access data,
8993 * and read the data into Records.
8995 Roo.data.Store = function(config){
8996 this.data = new Roo.util.MixedCollection(false);
8997 this.data.getKey = function(o){
9000 this.baseParams = {};
9007 "multisort" : "_multisort"
9010 if(config && config.data){
9011 this.inlineData = config.data;
9015 Roo.apply(this, config);
9017 if(this.reader){ // reader passed
9018 this.reader = Roo.factory(this.reader, Roo.data);
9019 this.reader.xmodule = this.xmodule || false;
9020 if(!this.recordType){
9021 this.recordType = this.reader.recordType;
9023 if(this.reader.onMetaChange){
9024 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9028 if(this.recordType){
9029 this.fields = this.recordType.prototype.fields;
9035 * @event datachanged
9036 * Fires when the data cache has changed, and a widget which is using this Store
9037 * as a Record cache should refresh its view.
9038 * @param {Store} this
9043 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9044 * @param {Store} this
9045 * @param {Object} meta The JSON metadata
9050 * Fires when Records have been added to the Store
9051 * @param {Store} this
9052 * @param {Roo.data.Record[]} records The array of Records added
9053 * @param {Number} index The index at which the record(s) were added
9058 * Fires when a Record has been removed from the Store
9059 * @param {Store} this
9060 * @param {Roo.data.Record} record The Record that was removed
9061 * @param {Number} index The index at which the record was removed
9066 * Fires when a Record has been updated
9067 * @param {Store} this
9068 * @param {Roo.data.Record} record The Record that was updated
9069 * @param {String} operation The update operation being performed. Value may be one of:
9071 Roo.data.Record.EDIT
9072 Roo.data.Record.REJECT
9073 Roo.data.Record.COMMIT
9079 * Fires when the data cache has been cleared.
9080 * @param {Store} this
9085 * Fires before a request is made for a new data object. If the beforeload handler returns false
9086 * the load action will be canceled.
9087 * @param {Store} this
9088 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9092 * @event beforeloadadd
9093 * Fires after a new set of Records has been loaded.
9094 * @param {Store} this
9095 * @param {Roo.data.Record[]} records The Records that were loaded
9096 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9098 beforeloadadd : true,
9101 * Fires after a new set of Records has been loaded, before they are added to the store.
9102 * @param {Store} this
9103 * @param {Roo.data.Record[]} records The Records that were loaded
9104 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9105 * @params {Object} return from reader
9109 * @event loadexception
9110 * Fires if an exception occurs in the Proxy during loading.
9111 * Called with the signature of the Proxy's "loadexception" event.
9112 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9115 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9116 * @param {Object} load options
9117 * @param {Object} jsonData from your request (normally this contains the Exception)
9119 loadexception : true
9123 this.proxy = Roo.factory(this.proxy, Roo.data);
9124 this.proxy.xmodule = this.xmodule || false;
9125 this.relayEvents(this.proxy, ["loadexception"]);
9127 this.sortToggle = {};
9128 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9130 Roo.data.Store.superclass.constructor.call(this);
9132 if(this.inlineData){
9133 this.loadData(this.inlineData);
9134 delete this.inlineData;
9138 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9140 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9141 * without a remote query - used by combo/forms at present.
9145 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9148 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9151 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9152 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9155 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9156 * on any HTTP request
9159 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9162 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9166 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9167 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9172 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9173 * loaded or when a record is removed. (defaults to false).
9175 pruneModifiedRecords : false,
9181 * Add Records to the Store and fires the add event.
9182 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9184 add : function(records){
9185 records = [].concat(records);
9186 for(var i = 0, len = records.length; i < len; i++){
9187 records[i].join(this);
9189 var index = this.data.length;
9190 this.data.addAll(records);
9191 this.fireEvent("add", this, records, index);
9195 * Remove a Record from the Store and fires the remove event.
9196 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9198 remove : function(record){
9199 var index = this.data.indexOf(record);
9200 this.data.removeAt(index);
9201 if(this.pruneModifiedRecords){
9202 this.modified.remove(record);
9204 this.fireEvent("remove", this, record, index);
9208 * Remove all Records from the Store and fires the clear event.
9210 removeAll : function(){
9212 if(this.pruneModifiedRecords){
9215 this.fireEvent("clear", this);
9219 * Inserts Records to the Store at the given index and fires the add event.
9220 * @param {Number} index The start index at which to insert the passed Records.
9221 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9223 insert : function(index, records){
9224 records = [].concat(records);
9225 for(var i = 0, len = records.length; i < len; i++){
9226 this.data.insert(index, records[i]);
9227 records[i].join(this);
9229 this.fireEvent("add", this, records, index);
9233 * Get the index within the cache of the passed Record.
9234 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9235 * @return {Number} The index of the passed Record. Returns -1 if not found.
9237 indexOf : function(record){
9238 return this.data.indexOf(record);
9242 * Get the index within the cache of the Record with the passed id.
9243 * @param {String} id The id of the Record to find.
9244 * @return {Number} The index of the Record. Returns -1 if not found.
9246 indexOfId : function(id){
9247 return this.data.indexOfKey(id);
9251 * Get the Record with the specified id.
9252 * @param {String} id The id of the Record to find.
9253 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9255 getById : function(id){
9256 return this.data.key(id);
9260 * Get the Record at the specified index.
9261 * @param {Number} index The index of the Record to find.
9262 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9264 getAt : function(index){
9265 return this.data.itemAt(index);
9269 * Returns a range of Records between specified indices.
9270 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9271 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9272 * @return {Roo.data.Record[]} An array of Records
9274 getRange : function(start, end){
9275 return this.data.getRange(start, end);
9279 storeOptions : function(o){
9280 o = Roo.apply({}, o);
9283 this.lastOptions = o;
9287 * Loads the Record cache from the configured Proxy using the configured Reader.
9289 * If using remote paging, then the first load call must specify the <em>start</em>
9290 * and <em>limit</em> properties in the options.params property to establish the initial
9291 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9293 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9294 * and this call will return before the new data has been loaded. Perform any post-processing
9295 * in a callback function, or in a "load" event handler.</strong>
9297 * @param {Object} options An object containing properties which control loading options:<ul>
9298 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9299 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9300 * passed the following arguments:<ul>
9301 * <li>r : Roo.data.Record[]</li>
9302 * <li>options: Options object from the load call</li>
9303 * <li>success: Boolean success indicator</li></ul></li>
9304 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9305 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9308 load : function(options){
9309 options = options || {};
9310 if(this.fireEvent("beforeload", this, options) !== false){
9311 this.storeOptions(options);
9312 var p = Roo.apply(options.params || {}, this.baseParams);
9313 // if meta was not loaded from remote source.. try requesting it.
9314 if (!this.reader.metaFromRemote) {
9317 if(this.sortInfo && this.remoteSort){
9318 var pn = this.paramNames;
9319 p[pn["sort"]] = this.sortInfo.field;
9320 p[pn["dir"]] = this.sortInfo.direction;
9322 if (this.multiSort) {
9323 var pn = this.paramNames;
9324 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9327 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9332 * Reloads the Record cache from the configured Proxy using the configured Reader and
9333 * the options from the last load operation performed.
9334 * @param {Object} options (optional) An object containing properties which may override the options
9335 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9336 * the most recently used options are reused).
9338 reload : function(options){
9339 this.load(Roo.applyIf(options||{}, this.lastOptions));
9343 // Called as a callback by the Reader during a load operation.
9344 loadRecords : function(o, options, success){
9345 if(!o || success === false){
9346 if(success !== false){
9347 this.fireEvent("load", this, [], options, o);
9349 if(options.callback){
9350 options.callback.call(options.scope || this, [], options, false);
9354 // if data returned failure - throw an exception.
9355 if (o.success === false) {
9356 // show a message if no listener is registered.
9357 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9358 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9360 // loadmask wil be hooked into this..
9361 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9364 var r = o.records, t = o.totalRecords || r.length;
9366 this.fireEvent("beforeloadadd", this, r, options, o);
9368 if(!options || options.add !== true){
9369 if(this.pruneModifiedRecords){
9372 for(var i = 0, len = r.length; i < len; i++){
9376 this.data = this.snapshot;
9377 delete this.snapshot;
9380 this.data.addAll(r);
9381 this.totalLength = t;
9383 this.fireEvent("datachanged", this);
9385 this.totalLength = Math.max(t, this.data.length+r.length);
9388 this.fireEvent("load", this, r, options, o);
9389 if(options.callback){
9390 options.callback.call(options.scope || this, r, options, true);
9396 * Loads data from a passed data block. A Reader which understands the format of the data
9397 * must have been configured in the constructor.
9398 * @param {Object} data The data block from which to read the Records. The format of the data expected
9399 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9400 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9402 loadData : function(o, append){
9403 var r = this.reader.readRecords(o);
9404 this.loadRecords(r, {add: append}, true);
9408 * Gets the number of cached records.
9410 * <em>If using paging, this may not be the total size of the dataset. If the data object
9411 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9412 * the data set size</em>
9414 getCount : function(){
9415 return this.data.length || 0;
9419 * Gets the total number of records in the dataset as returned by the server.
9421 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9422 * the dataset size</em>
9424 getTotalCount : function(){
9425 return this.totalLength || 0;
9429 * Returns the sort state of the Store as an object with two properties:
9431 field {String} The name of the field by which the Records are sorted
9432 direction {String} The sort order, "ASC" or "DESC"
9435 getSortState : function(){
9436 return this.sortInfo;
9440 applySort : function(){
9441 if(this.sortInfo && !this.remoteSort){
9442 var s = this.sortInfo, f = s.field;
9443 var st = this.fields.get(f).sortType;
9444 var fn = function(r1, r2){
9445 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9446 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9448 this.data.sort(s.direction, fn);
9449 if(this.snapshot && this.snapshot != this.data){
9450 this.snapshot.sort(s.direction, fn);
9456 * Sets the default sort column and order to be used by the next load operation.
9457 * @param {String} fieldName The name of the field to sort by.
9458 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9460 setDefaultSort : function(field, dir){
9461 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9466 * If remote sorting is used, the sort is performed on the server, and the cache is
9467 * reloaded. If local sorting is used, the cache is sorted internally.
9468 * @param {String} fieldName The name of the field to sort by.
9469 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9471 sort : function(fieldName, dir){
9472 var f = this.fields.get(fieldName);
9474 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9476 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9477 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9482 this.sortToggle[f.name] = dir;
9483 this.sortInfo = {field: f.name, direction: dir};
9484 if(!this.remoteSort){
9486 this.fireEvent("datachanged", this);
9488 this.load(this.lastOptions);
9493 * Calls the specified function for each of the Records in the cache.
9494 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9495 * Returning <em>false</em> aborts and exits the iteration.
9496 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9498 each : function(fn, scope){
9499 this.data.each(fn, scope);
9503 * Gets all records modified since the last commit. Modified records are persisted across load operations
9504 * (e.g., during paging).
9505 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9507 getModifiedRecords : function(){
9508 return this.modified;
9512 createFilterFn : function(property, value, anyMatch){
9513 if(!value.exec){ // not a regex
9514 value = String(value);
9515 if(value.length == 0){
9518 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9521 return value.test(r.data[property]);
9526 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9527 * @param {String} property A field on your records
9528 * @param {Number} start The record index to start at (defaults to 0)
9529 * @param {Number} end The last record index to include (defaults to length - 1)
9530 * @return {Number} The sum
9532 sum : function(property, start, end){
9533 var rs = this.data.items, v = 0;
9535 end = (end || end === 0) ? end : rs.length-1;
9537 for(var i = start; i <= end; i++){
9538 v += (rs[i].data[property] || 0);
9544 * Filter the records by a specified property.
9545 * @param {String} field A field on your records
9546 * @param {String/RegExp} value Either a string that the field
9547 * should start with or a RegExp to test against the field
9548 * @param {Boolean} anyMatch True to match any part not just the beginning
9550 filter : function(property, value, anyMatch){
9551 var fn = this.createFilterFn(property, value, anyMatch);
9552 return fn ? this.filterBy(fn) : this.clearFilter();
9556 * Filter by a function. The specified function will be called with each
9557 * record in this data source. If the function returns true the record is included,
9558 * otherwise it is filtered.
9559 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9560 * @param {Object} scope (optional) The scope of the function (defaults to this)
9562 filterBy : function(fn, scope){
9563 this.snapshot = this.snapshot || this.data;
9564 this.data = this.queryBy(fn, scope||this);
9565 this.fireEvent("datachanged", this);
9569 * Query the records by a specified property.
9570 * @param {String} field A field on your records
9571 * @param {String/RegExp} value Either a string that the field
9572 * should start with or a RegExp to test against the field
9573 * @param {Boolean} anyMatch True to match any part not just the beginning
9574 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9576 query : function(property, value, anyMatch){
9577 var fn = this.createFilterFn(property, value, anyMatch);
9578 return fn ? this.queryBy(fn) : this.data.clone();
9582 * Query by a function. The specified function will be called with each
9583 * record in this data source. If the function returns true the record is included
9585 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9586 * @param {Object} scope (optional) The scope of the function (defaults to this)
9587 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9589 queryBy : function(fn, scope){
9590 var data = this.snapshot || this.data;
9591 return data.filterBy(fn, scope||this);
9595 * Collects unique values for a particular dataIndex from this store.
9596 * @param {String} dataIndex The property to collect
9597 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9598 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9599 * @return {Array} An array of the unique values
9601 collect : function(dataIndex, allowNull, bypassFilter){
9602 var d = (bypassFilter === true && this.snapshot) ?
9603 this.snapshot.items : this.data.items;
9604 var v, sv, r = [], l = {};
9605 for(var i = 0, len = d.length; i < len; i++){
9606 v = d[i].data[dataIndex];
9608 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9617 * Revert to a view of the Record cache with no filtering applied.
9618 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9620 clearFilter : function(suppressEvent){
9621 if(this.snapshot && this.snapshot != this.data){
9622 this.data = this.snapshot;
9623 delete this.snapshot;
9624 if(suppressEvent !== true){
9625 this.fireEvent("datachanged", this);
9631 afterEdit : function(record){
9632 if(this.modified.indexOf(record) == -1){
9633 this.modified.push(record);
9635 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9639 afterReject : function(record){
9640 this.modified.remove(record);
9641 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9645 afterCommit : function(record){
9646 this.modified.remove(record);
9647 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9651 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9652 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9654 commitChanges : function(){
9655 var m = this.modified.slice(0);
9657 for(var i = 0, len = m.length; i < len; i++){
9663 * Cancel outstanding changes on all changed records.
9665 rejectChanges : function(){
9666 var m = this.modified.slice(0);
9668 for(var i = 0, len = m.length; i < len; i++){
9673 onMetaChange : function(meta, rtype, o){
9674 this.recordType = rtype;
9675 this.fields = rtype.prototype.fields;
9676 delete this.snapshot;
9677 this.sortInfo = meta.sortInfo || this.sortInfo;
9679 this.fireEvent('metachange', this, this.reader.meta);
9682 moveIndex : function(data, type)
9684 var index = this.indexOf(data);
9686 var newIndex = index + type;
9690 this.insert(newIndex, data);
9695 * Ext JS Library 1.1.1
9696 * Copyright(c) 2006-2007, Ext JS, LLC.
9698 * Originally Released Under LGPL - original licence link has changed is not relivant.
9701 * <script type="text/javascript">
9705 * @class Roo.data.SimpleStore
9706 * @extends Roo.data.Store
9707 * Small helper class to make creating Stores from Array data easier.
9708 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9709 * @cfg {Array} fields An array of field definition objects, or field name strings.
9710 * @cfg {Array} data The multi-dimensional array of data
9712 * @param {Object} config
9714 Roo.data.SimpleStore = function(config){
9715 Roo.data.SimpleStore.superclass.constructor.call(this, {
9717 reader: new Roo.data.ArrayReader({
9720 Roo.data.Record.create(config.fields)
9722 proxy : new Roo.data.MemoryProxy(config.data)
9726 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9728 * Ext JS Library 1.1.1
9729 * Copyright(c) 2006-2007, Ext JS, LLC.
9731 * Originally Released Under LGPL - original licence link has changed is not relivant.
9734 * <script type="text/javascript">
9739 * @extends Roo.data.Store
9740 * @class Roo.data.JsonStore
9741 * Small helper class to make creating Stores for JSON data easier. <br/>
9743 var store = new Roo.data.JsonStore({
9744 url: 'get-images.php',
9746 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9749 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9750 * JsonReader and HttpProxy (unless inline data is provided).</b>
9751 * @cfg {Array} fields An array of field definition objects, or field name strings.
9753 * @param {Object} config
9755 Roo.data.JsonStore = function(c){
9756 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9757 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9758 reader: new Roo.data.JsonReader(c, c.fields)
9761 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9763 * Ext JS Library 1.1.1
9764 * Copyright(c) 2006-2007, Ext JS, LLC.
9766 * Originally Released Under LGPL - original licence link has changed is not relivant.
9769 * <script type="text/javascript">
9773 Roo.data.Field = function(config){
9774 if(typeof config == "string"){
9775 config = {name: config};
9777 Roo.apply(this, config);
9783 var st = Roo.data.SortTypes;
9784 // named sortTypes are supported, here we look them up
9785 if(typeof this.sortType == "string"){
9786 this.sortType = st[this.sortType];
9789 // set default sortType for strings and dates
9793 this.sortType = st.asUCString;
9796 this.sortType = st.asDate;
9799 this.sortType = st.none;
9804 var stripRe = /[\$,%]/g;
9806 // prebuilt conversion function for this field, instead of
9807 // switching every time we're reading a value
9809 var cv, dateFormat = this.dateFormat;
9814 cv = function(v){ return v; };
9817 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9821 return v !== undefined && v !== null && v !== '' ?
9822 parseInt(String(v).replace(stripRe, ""), 10) : '';
9827 return v !== undefined && v !== null && v !== '' ?
9828 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9833 cv = function(v){ return v === true || v === "true" || v == 1; };
9840 if(v instanceof Date){
9844 if(dateFormat == "timestamp"){
9845 return new Date(v*1000);
9847 return Date.parseDate(v, dateFormat);
9849 var parsed = Date.parse(v);
9850 return parsed ? new Date(parsed) : null;
9859 Roo.data.Field.prototype = {
9867 * Ext JS Library 1.1.1
9868 * Copyright(c) 2006-2007, Ext JS, LLC.
9870 * Originally Released Under LGPL - original licence link has changed is not relivant.
9873 * <script type="text/javascript">
9876 // Base class for reading structured data from a data source. This class is intended to be
9877 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9880 * @class Roo.data.DataReader
9881 * Base class for reading structured data from a data source. This class is intended to be
9882 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9885 Roo.data.DataReader = function(meta, recordType){
9889 this.recordType = recordType instanceof Array ?
9890 Roo.data.Record.create(recordType) : recordType;
9893 Roo.data.DataReader.prototype = {
9895 * Create an empty record
9896 * @param {Object} data (optional) - overlay some values
9897 * @return {Roo.data.Record} record created.
9899 newRow : function(d) {
9901 this.recordType.prototype.fields.each(function(c) {
9903 case 'int' : da[c.name] = 0; break;
9904 case 'date' : da[c.name] = new Date(); break;
9905 case 'float' : da[c.name] = 0.0; break;
9906 case 'boolean' : da[c.name] = false; break;
9907 default : da[c.name] = ""; break;
9911 return new this.recordType(Roo.apply(da, d));
9916 * Ext JS Library 1.1.1
9917 * Copyright(c) 2006-2007, Ext JS, LLC.
9919 * Originally Released Under LGPL - original licence link has changed is not relivant.
9922 * <script type="text/javascript">
9926 * @class Roo.data.DataProxy
9927 * @extends Roo.data.Observable
9928 * This class is an abstract base class for implementations which provide retrieval of
9929 * unformatted data objects.<br>
9931 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9932 * (of the appropriate type which knows how to parse the data object) to provide a block of
9933 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9935 * Custom implementations must implement the load method as described in
9936 * {@link Roo.data.HttpProxy#load}.
9938 Roo.data.DataProxy = function(){
9942 * Fires before a network request is made to retrieve a data object.
9943 * @param {Object} This DataProxy object.
9944 * @param {Object} params The params parameter to the load function.
9949 * Fires before the load method's callback is called.
9950 * @param {Object} This DataProxy object.
9951 * @param {Object} o The data object.
9952 * @param {Object} arg The callback argument object passed to the load function.
9956 * @event loadexception
9957 * Fires if an Exception occurs during data retrieval.
9958 * @param {Object} This DataProxy object.
9959 * @param {Object} o The data object.
9960 * @param {Object} arg The callback argument object passed to the load function.
9961 * @param {Object} e The Exception.
9963 loadexception : true
9965 Roo.data.DataProxy.superclass.constructor.call(this);
9968 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9971 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9975 * Ext JS Library 1.1.1
9976 * Copyright(c) 2006-2007, Ext JS, LLC.
9978 * Originally Released Under LGPL - original licence link has changed is not relivant.
9981 * <script type="text/javascript">
9984 * @class Roo.data.MemoryProxy
9985 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9986 * to the Reader when its load method is called.
9988 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9990 Roo.data.MemoryProxy = function(data){
9994 Roo.data.MemoryProxy.superclass.constructor.call(this);
9998 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10000 * Load data from the requested source (in this case an in-memory
10001 * data object passed to the constructor), read the data object into
10002 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10003 * process that block using the passed callback.
10004 * @param {Object} params This parameter is not used by the MemoryProxy class.
10005 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10006 * object into a block of Roo.data.Records.
10007 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10008 * The function must be passed <ul>
10009 * <li>The Record block object</li>
10010 * <li>The "arg" argument from the load function</li>
10011 * <li>A boolean success indicator</li>
10013 * @param {Object} scope The scope in which to call the callback
10014 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10016 load : function(params, reader, callback, scope, arg){
10017 params = params || {};
10020 result = reader.readRecords(this.data);
10022 this.fireEvent("loadexception", this, arg, null, e);
10023 callback.call(scope, null, arg, false);
10026 callback.call(scope, result, arg, true);
10030 update : function(params, records){
10035 * Ext JS Library 1.1.1
10036 * Copyright(c) 2006-2007, Ext JS, LLC.
10038 * Originally Released Under LGPL - original licence link has changed is not relivant.
10041 * <script type="text/javascript">
10044 * @class Roo.data.HttpProxy
10045 * @extends Roo.data.DataProxy
10046 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10047 * configured to reference a certain URL.<br><br>
10049 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10050 * from which the running page was served.<br><br>
10052 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10054 * Be aware that to enable the browser to parse an XML document, the server must set
10055 * the Content-Type header in the HTTP response to "text/xml".
10057 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10058 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10059 * will be used to make the request.
10061 Roo.data.HttpProxy = function(conn){
10062 Roo.data.HttpProxy.superclass.constructor.call(this);
10063 // is conn a conn config or a real conn?
10065 this.useAjax = !conn || !conn.events;
10069 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10070 // thse are take from connection...
10073 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10076 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10077 * extra parameters to each request made by this object. (defaults to undefined)
10080 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10081 * to each request made by this object. (defaults to undefined)
10084 * @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)
10087 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10090 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10096 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10100 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10101 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10102 * a finer-grained basis than the DataProxy events.
10104 getConnection : function(){
10105 return this.useAjax ? Roo.Ajax : this.conn;
10109 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10110 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10111 * process that block using the passed callback.
10112 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10113 * for the request to the remote server.
10114 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10115 * object into a block of Roo.data.Records.
10116 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10117 * The function must be passed <ul>
10118 * <li>The Record block object</li>
10119 * <li>The "arg" argument from the load function</li>
10120 * <li>A boolean success indicator</li>
10122 * @param {Object} scope The scope in which to call the callback
10123 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10125 load : function(params, reader, callback, scope, arg){
10126 if(this.fireEvent("beforeload", this, params) !== false){
10128 params : params || {},
10130 callback : callback,
10135 callback : this.loadResponse,
10139 Roo.applyIf(o, this.conn);
10140 if(this.activeRequest){
10141 Roo.Ajax.abort(this.activeRequest);
10143 this.activeRequest = Roo.Ajax.request(o);
10145 this.conn.request(o);
10148 callback.call(scope||this, null, arg, false);
10153 loadResponse : function(o, success, response){
10154 delete this.activeRequest;
10156 this.fireEvent("loadexception", this, o, response);
10157 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10162 result = o.reader.read(response);
10164 this.fireEvent("loadexception", this, o, response, e);
10165 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10169 this.fireEvent("load", this, o, o.request.arg);
10170 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10174 update : function(dataSet){
10179 updateResponse : function(dataSet){
10184 * Ext JS Library 1.1.1
10185 * Copyright(c) 2006-2007, Ext JS, LLC.
10187 * Originally Released Under LGPL - original licence link has changed is not relivant.
10190 * <script type="text/javascript">
10194 * @class Roo.data.ScriptTagProxy
10195 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10196 * other than the originating domain of the running page.<br><br>
10198 * <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
10199 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10201 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10202 * source code that is used as the source inside a <script> tag.<br><br>
10204 * In order for the browser to process the returned data, the server must wrap the data object
10205 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10206 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10207 * depending on whether the callback name was passed:
10210 boolean scriptTag = false;
10211 String cb = request.getParameter("callback");
10214 response.setContentType("text/javascript");
10216 response.setContentType("application/x-json");
10218 Writer out = response.getWriter();
10220 out.write(cb + "(");
10222 out.print(dataBlock.toJsonString());
10229 * @param {Object} config A configuration object.
10231 Roo.data.ScriptTagProxy = function(config){
10232 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10233 Roo.apply(this, config);
10234 this.head = document.getElementsByTagName("head")[0];
10237 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10239 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10241 * @cfg {String} url The URL from which to request the data object.
10244 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10248 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10249 * the server the name of the callback function set up by the load call to process the returned data object.
10250 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10251 * javascript output which calls this named function passing the data object as its only parameter.
10253 callbackParam : "callback",
10255 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10256 * name to the request.
10261 * Load data from the configured URL, read the data object into
10262 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10263 * process that block using the passed callback.
10264 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10265 * for the request to the remote server.
10266 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10267 * object into a block of Roo.data.Records.
10268 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10269 * The function must be passed <ul>
10270 * <li>The Record block object</li>
10271 * <li>The "arg" argument from the load function</li>
10272 * <li>A boolean success indicator</li>
10274 * @param {Object} scope The scope in which to call the callback
10275 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10277 load : function(params, reader, callback, scope, arg){
10278 if(this.fireEvent("beforeload", this, params) !== false){
10280 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10282 var url = this.url;
10283 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10285 url += "&_dc=" + (new Date().getTime());
10287 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10290 cb : "stcCallback"+transId,
10291 scriptId : "stcScript"+transId,
10295 callback : callback,
10301 window[trans.cb] = function(o){
10302 conn.handleResponse(o, trans);
10305 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10307 if(this.autoAbort !== false){
10311 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10313 var script = document.createElement("script");
10314 script.setAttribute("src", url);
10315 script.setAttribute("type", "text/javascript");
10316 script.setAttribute("id", trans.scriptId);
10317 this.head.appendChild(script);
10319 this.trans = trans;
10321 callback.call(scope||this, null, arg, false);
10326 isLoading : function(){
10327 return this.trans ? true : false;
10331 * Abort the current server request.
10333 abort : function(){
10334 if(this.isLoading()){
10335 this.destroyTrans(this.trans);
10340 destroyTrans : function(trans, isLoaded){
10341 this.head.removeChild(document.getElementById(trans.scriptId));
10342 clearTimeout(trans.timeoutId);
10344 window[trans.cb] = undefined;
10346 delete window[trans.cb];
10349 // if hasn't been loaded, wait for load to remove it to prevent script error
10350 window[trans.cb] = function(){
10351 window[trans.cb] = undefined;
10353 delete window[trans.cb];
10360 handleResponse : function(o, trans){
10361 this.trans = false;
10362 this.destroyTrans(trans, true);
10365 result = trans.reader.readRecords(o);
10367 this.fireEvent("loadexception", this, o, trans.arg, e);
10368 trans.callback.call(trans.scope||window, null, trans.arg, false);
10371 this.fireEvent("load", this, o, trans.arg);
10372 trans.callback.call(trans.scope||window, result, trans.arg, true);
10376 handleFailure : function(trans){
10377 this.trans = false;
10378 this.destroyTrans(trans, false);
10379 this.fireEvent("loadexception", this, null, trans.arg);
10380 trans.callback.call(trans.scope||window, null, trans.arg, false);
10384 * Ext JS Library 1.1.1
10385 * Copyright(c) 2006-2007, Ext JS, LLC.
10387 * Originally Released Under LGPL - original licence link has changed is not relivant.
10390 * <script type="text/javascript">
10394 * @class Roo.data.JsonReader
10395 * @extends Roo.data.DataReader
10396 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10397 * based on mappings in a provided Roo.data.Record constructor.
10399 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10400 * in the reply previously.
10405 var RecordDef = Roo.data.Record.create([
10406 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10407 {name: 'occupation'} // This field will use "occupation" as the mapping.
10409 var myReader = new Roo.data.JsonReader({
10410 totalProperty: "results", // The property which contains the total dataset size (optional)
10411 root: "rows", // The property which contains an Array of row objects
10412 id: "id" // The property within each row object that provides an ID for the record (optional)
10416 * This would consume a JSON file like this:
10418 { 'results': 2, 'rows': [
10419 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10420 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10423 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10424 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10425 * paged from the remote server.
10426 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10427 * @cfg {String} root name of the property which contains the Array of row objects.
10428 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10430 * Create a new JsonReader
10431 * @param {Object} meta Metadata configuration options
10432 * @param {Object} recordType Either an Array of field definition objects,
10433 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10435 Roo.data.JsonReader = function(meta, recordType){
10438 // set some defaults:
10439 Roo.applyIf(meta, {
10440 totalProperty: 'total',
10441 successProperty : 'success',
10446 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10448 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10451 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10452 * Used by Store query builder to append _requestMeta to params.
10455 metaFromRemote : false,
10457 * This method is only used by a DataProxy which has retrieved data from a remote server.
10458 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10459 * @return {Object} data A data block which is used by an Roo.data.Store object as
10460 * a cache of Roo.data.Records.
10462 read : function(response){
10463 var json = response.responseText;
10465 var o = /* eval:var:o */ eval("("+json+")");
10467 throw {message: "JsonReader.read: Json object not found"};
10473 this.metaFromRemote = true;
10474 this.meta = o.metaData;
10475 this.recordType = Roo.data.Record.create(o.metaData.fields);
10476 this.onMetaChange(this.meta, this.recordType, o);
10478 return this.readRecords(o);
10481 // private function a store will implement
10482 onMetaChange : function(meta, recordType, o){
10489 simpleAccess: function(obj, subsc) {
10496 getJsonAccessor: function(){
10498 return function(expr) {
10500 return(re.test(expr))
10501 ? new Function("obj", "return obj." + expr)
10506 return Roo.emptyFn;
10511 * Create a data block containing Roo.data.Records from an XML document.
10512 * @param {Object} o An object which contains an Array of row objects in the property specified
10513 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10514 * which contains the total size of the dataset.
10515 * @return {Object} data A data block which is used by an Roo.data.Store object as
10516 * a cache of Roo.data.Records.
10518 readRecords : function(o){
10520 * After any data loads, the raw JSON data is available for further custom processing.
10524 var s = this.meta, Record = this.recordType,
10525 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10527 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10529 if(s.totalProperty) {
10530 this.getTotal = this.getJsonAccessor(s.totalProperty);
10532 if(s.successProperty) {
10533 this.getSuccess = this.getJsonAccessor(s.successProperty);
10535 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10537 var g = this.getJsonAccessor(s.id);
10538 this.getId = function(rec) {
10540 return (r === undefined || r === "") ? null : r;
10543 this.getId = function(){return null;};
10546 for(var jj = 0; jj < fl; jj++){
10548 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10549 this.ef[jj] = this.getJsonAccessor(map);
10553 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10554 if(s.totalProperty){
10555 var vt = parseInt(this.getTotal(o), 10);
10560 if(s.successProperty){
10561 var vs = this.getSuccess(o);
10562 if(vs === false || vs === 'false'){
10567 for(var i = 0; i < c; i++){
10570 var id = this.getId(n);
10571 for(var j = 0; j < fl; j++){
10573 var v = this.ef[j](n);
10575 Roo.log('missing convert for ' + f.name);
10579 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10581 var record = new Record(values, id);
10583 records[i] = record;
10589 totalRecords : totalRecords
10594 * Ext JS Library 1.1.1
10595 * Copyright(c) 2006-2007, Ext JS, LLC.
10597 * Originally Released Under LGPL - original licence link has changed is not relivant.
10600 * <script type="text/javascript">
10604 * @class Roo.data.ArrayReader
10605 * @extends Roo.data.DataReader
10606 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10607 * Each element of that Array represents a row of data fields. The
10608 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10609 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10613 var RecordDef = Roo.data.Record.create([
10614 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10615 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10617 var myReader = new Roo.data.ArrayReader({
10618 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10622 * This would consume an Array like this:
10624 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10626 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10628 * Create a new JsonReader
10629 * @param {Object} meta Metadata configuration options.
10630 * @param {Object} recordType Either an Array of field definition objects
10631 * as specified to {@link Roo.data.Record#create},
10632 * or an {@link Roo.data.Record} object
10633 * created using {@link Roo.data.Record#create}.
10635 Roo.data.ArrayReader = function(meta, recordType){
10636 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10639 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10641 * Create a data block containing Roo.data.Records from an XML document.
10642 * @param {Object} o An Array of row objects which represents the dataset.
10643 * @return {Object} data A data block which is used by an Roo.data.Store object as
10644 * a cache of Roo.data.Records.
10646 readRecords : function(o){
10647 var sid = this.meta ? this.meta.id : null;
10648 var recordType = this.recordType, fields = recordType.prototype.fields;
10651 for(var i = 0; i < root.length; i++){
10654 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10655 for(var j = 0, jlen = fields.length; j < jlen; j++){
10656 var f = fields.items[j];
10657 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10658 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10660 values[f.name] = v;
10662 var record = new recordType(values, id);
10664 records[records.length] = record;
10668 totalRecords : records.length
10677 * @class Roo.bootstrap.ComboBox
10678 * @extends Roo.bootstrap.TriggerField
10679 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10680 * @cfg {Boolean} append (true|false) default false
10681 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10682 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10683 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10684 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10685 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10687 * Create a new ComboBox.
10688 * @param {Object} config Configuration options
10690 Roo.bootstrap.ComboBox = function(config){
10691 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10695 * Fires when the dropdown list is expanded
10696 * @param {Roo.bootstrap.ComboBox} combo This combo box
10701 * Fires when the dropdown list is collapsed
10702 * @param {Roo.bootstrap.ComboBox} combo This combo box
10706 * @event beforeselect
10707 * Fires before a list item is selected. Return false to cancel the selection.
10708 * @param {Roo.bootstrap.ComboBox} combo This combo box
10709 * @param {Roo.data.Record} record The data record returned from the underlying store
10710 * @param {Number} index The index of the selected item in the dropdown list
10712 'beforeselect' : true,
10715 * Fires when a list item is selected
10716 * @param {Roo.bootstrap.ComboBox} combo This combo box
10717 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10718 * @param {Number} index The index of the selected item in the dropdown list
10722 * @event beforequery
10723 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10724 * The event object passed has these properties:
10725 * @param {Roo.bootstrap.ComboBox} combo This combo box
10726 * @param {String} query The query
10727 * @param {Boolean} forceAll true to force "all" query
10728 * @param {Boolean} cancel true to cancel the query
10729 * @param {Object} e The query event object
10731 'beforequery': true,
10734 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10735 * @param {Roo.bootstrap.ComboBox} combo This combo box
10740 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10741 * @param {Roo.bootstrap.ComboBox} combo This combo box
10742 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10747 * Fires when the remove value from the combobox array
10748 * @param {Roo.bootstrap.ComboBox} combo This combo box
10755 this.tickItems = [];
10757 this.selectedIndex = -1;
10758 if(this.mode == 'local'){
10759 if(config.queryDelay === undefined){
10760 this.queryDelay = 10;
10762 if(config.minChars === undefined){
10768 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10771 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10772 * rendering into an Roo.Editor, defaults to false)
10775 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10776 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10779 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10782 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10783 * the dropdown list (defaults to undefined, with no header element)
10787 * @cfg {String/Roo.Template} tpl The template to use to render the output
10791 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10793 listWidth: undefined,
10795 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10796 * mode = 'remote' or 'text' if mode = 'local')
10798 displayField: undefined,
10800 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10801 * mode = 'remote' or 'value' if mode = 'local').
10802 * Note: use of a valueField requires the user make a selection
10803 * in order for a value to be mapped.
10805 valueField: undefined,
10809 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10810 * field's data value (defaults to the underlying DOM element's name)
10812 hiddenName: undefined,
10814 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10818 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10820 selectedClass: 'active',
10823 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10827 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10828 * anchor positions (defaults to 'tl-bl')
10830 listAlign: 'tl-bl?',
10832 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10836 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10837 * query specified by the allQuery config option (defaults to 'query')
10839 triggerAction: 'query',
10841 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10842 * (defaults to 4, does not apply if editable = false)
10846 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10847 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10851 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10852 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10856 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10857 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10861 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10862 * when editable = true (defaults to false)
10864 selectOnFocus:false,
10866 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10868 queryParam: 'query',
10870 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10871 * when mode = 'remote' (defaults to 'Loading...')
10873 loadingText: 'Loading...',
10875 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10879 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10883 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10884 * traditional select (defaults to true)
10888 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10892 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10896 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10897 * listWidth has a higher value)
10901 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10902 * allow the user to set arbitrary text into the field (defaults to false)
10904 forceSelection:false,
10906 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10907 * if typeAhead = true (defaults to 250)
10909 typeAheadDelay : 250,
10911 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10912 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10914 valueNotFoundText : undefined,
10916 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10918 blockFocus : false,
10921 * @cfg {Boolean} disableClear Disable showing of clear button.
10923 disableClear : false,
10925 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10927 alwaysQuery : false,
10930 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10935 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10937 invalidClass : "has-warning",
10940 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10942 validClass : "has-success",
10954 btnPosition : 'right',
10955 triggerList : true,
10956 showToggleBtn : true,
10957 // element that contains real text value.. (when hidden is used..)
10959 getAutoCreate : function()
10966 if(!this.tickable){
10967 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10972 * ComboBox with tickable selections
10975 var align = this.labelAlign || this.parentLabelAlign();
10978 cls : 'form-group roo-combobox-tickable' //input-group
10983 cls : 'tickable-buttons',
10988 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10995 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11002 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11009 buttons.cn.unshift({
11011 cls: 'select2-search-field-input'
11017 Roo.each(buttons.cn, function(c){
11019 c.cls += ' btn-' + _this.size;
11022 if (_this.disabled) {
11033 cls: 'form-hidden-field'
11037 cls: 'select2-choices',
11041 cls: 'select2-search-field',
11053 cls: 'select2-container input-group select2-container-multi',
11058 // cls: 'typeahead typeahead-long dropdown-menu',
11059 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11064 if(this.hasFeedback && !this.allowBlank){
11068 cls: 'glyphicon form-control-feedback'
11071 combobox.cn.push(feedback);
11074 if (align ==='left' && this.fieldLabel.length) {
11076 Roo.log("left and has label");
11082 cls : 'control-label col-sm-' + this.labelWidth,
11083 html : this.fieldLabel
11087 cls : "col-sm-" + (12 - this.labelWidth),
11094 } else if ( this.fieldLabel.length) {
11100 //cls : 'input-group-addon',
11101 html : this.fieldLabel
11111 Roo.log(" no label && no align");
11118 ['xs','sm','md','lg'].map(function(size){
11119 if (settings[size]) {
11120 cfg.cls += ' col-' + size + '-' + settings[size];
11129 initEvents: function()
11133 throw "can not find store for combo";
11135 this.store = Roo.factory(this.store, Roo.data);
11138 this.initTickableEvents();
11142 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11144 if(this.hiddenName){
11146 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11148 this.hiddenField.dom.value =
11149 this.hiddenValue !== undefined ? this.hiddenValue :
11150 this.value !== undefined ? this.value : '';
11152 // prevent input submission
11153 this.el.dom.removeAttribute('name');
11154 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11159 // this.el.dom.setAttribute('autocomplete', 'off');
11162 var cls = 'x-combo-list';
11164 //this.list = new Roo.Layer({
11165 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11171 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11172 _this.list.setWidth(lw);
11175 this.list.on('mouseover', this.onViewOver, this);
11176 this.list.on('mousemove', this.onViewMove, this);
11178 this.list.on('scroll', this.onViewScroll, this);
11181 this.list.swallowEvent('mousewheel');
11182 this.assetHeight = 0;
11185 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11186 this.assetHeight += this.header.getHeight();
11189 this.innerList = this.list.createChild({cls:cls+'-inner'});
11190 this.innerList.on('mouseover', this.onViewOver, this);
11191 this.innerList.on('mousemove', this.onViewMove, this);
11192 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11194 if(this.allowBlank && !this.pageSize && !this.disableClear){
11195 this.footer = this.list.createChild({cls:cls+'-ft'});
11196 this.pageTb = new Roo.Toolbar(this.footer);
11200 this.footer = this.list.createChild({cls:cls+'-ft'});
11201 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11202 {pageSize: this.pageSize});
11206 if (this.pageTb && this.allowBlank && !this.disableClear) {
11208 this.pageTb.add(new Roo.Toolbar.Fill(), {
11209 cls: 'x-btn-icon x-btn-clear',
11211 handler: function()
11214 _this.clearValue();
11215 _this.onSelect(false, -1);
11220 this.assetHeight += this.footer.getHeight();
11225 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11228 this.view = new Roo.View(this.list, this.tpl, {
11229 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11231 //this.view.wrapEl.setDisplayed(false);
11232 this.view.on('click', this.onViewClick, this);
11236 this.store.on('beforeload', this.onBeforeLoad, this);
11237 this.store.on('load', this.onLoad, this);
11238 this.store.on('loadexception', this.onLoadException, this);
11240 if(this.resizable){
11241 this.resizer = new Roo.Resizable(this.list, {
11242 pinned:true, handles:'se'
11244 this.resizer.on('resize', function(r, w, h){
11245 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11246 this.listWidth = w;
11247 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11248 this.restrictHeight();
11250 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11253 if(!this.editable){
11254 this.editable = true;
11255 this.setEditable(false);
11260 if (typeof(this.events.add.listeners) != 'undefined') {
11262 this.addicon = this.wrap.createChild(
11263 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11265 this.addicon.on('click', function(e) {
11266 this.fireEvent('add', this);
11269 if (typeof(this.events.edit.listeners) != 'undefined') {
11271 this.editicon = this.wrap.createChild(
11272 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11273 if (this.addicon) {
11274 this.editicon.setStyle('margin-left', '40px');
11276 this.editicon.on('click', function(e) {
11278 // we fire even if inothing is selected..
11279 this.fireEvent('edit', this, this.lastData );
11285 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11286 "up" : function(e){
11287 this.inKeyMode = true;
11291 "down" : function(e){
11292 if(!this.isExpanded()){
11293 this.onTriggerClick();
11295 this.inKeyMode = true;
11300 "enter" : function(e){
11301 // this.onViewClick();
11305 if(this.fireEvent("specialkey", this, e)){
11306 this.onViewClick(false);
11312 "esc" : function(e){
11316 "tab" : function(e){
11319 if(this.fireEvent("specialkey", this, e)){
11320 this.onViewClick(false);
11328 doRelay : function(foo, bar, hname){
11329 if(hname == 'down' || this.scope.isExpanded()){
11330 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11339 this.queryDelay = Math.max(this.queryDelay || 10,
11340 this.mode == 'local' ? 10 : 250);
11343 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11345 if(this.typeAhead){
11346 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11348 if(this.editable !== false){
11349 this.inputEl().on("keyup", this.onKeyUp, this);
11351 if(this.forceSelection){
11352 this.inputEl().on('blur', this.doForce, this);
11356 this.choices = this.el.select('ul.select2-choices', true).first();
11357 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11361 initTickableEvents: function()
11365 if(this.hiddenName){
11367 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11369 this.hiddenField.dom.value =
11370 this.hiddenValue !== undefined ? this.hiddenValue :
11371 this.value !== undefined ? this.value : '';
11373 // prevent input submission
11374 this.el.dom.removeAttribute('name');
11375 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11380 // this.list = this.el.select('ul.dropdown-menu',true).first();
11382 this.choices = this.el.select('ul.select2-choices', true).first();
11383 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11384 if(this.triggerList){
11385 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11388 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11389 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11391 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11392 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11394 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11395 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11397 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11398 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11399 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11402 this.cancelBtn.hide();
11407 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11408 _this.list.setWidth(lw);
11411 this.list.on('mouseover', this.onViewOver, this);
11412 this.list.on('mousemove', this.onViewMove, this);
11414 this.list.on('scroll', this.onViewScroll, this);
11417 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>';
11420 this.view = new Roo.View(this.list, this.tpl, {
11421 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11424 //this.view.wrapEl.setDisplayed(false);
11425 this.view.on('click', this.onViewClick, this);
11429 this.store.on('beforeload', this.onBeforeLoad, this);
11430 this.store.on('load', this.onLoad, this);
11431 this.store.on('loadexception', this.onLoadException, this);
11434 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11435 "up" : function(e){
11436 this.inKeyMode = true;
11440 "down" : function(e){
11441 this.inKeyMode = true;
11445 "enter" : function(e){
11446 if(this.fireEvent("specialkey", this, e)){
11447 this.onViewClick(false);
11453 "esc" : function(e){
11454 this.onTickableFooterButtonClick(e, false, false);
11457 "tab" : function(e){
11458 this.fireEvent("specialkey", this, e);
11460 this.onTickableFooterButtonClick(e, false, false);
11467 doRelay : function(e, fn, key){
11468 if(this.scope.isExpanded()){
11469 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11478 this.queryDelay = Math.max(this.queryDelay || 10,
11479 this.mode == 'local' ? 10 : 250);
11482 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11484 if(this.typeAhead){
11485 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11488 if(this.editable !== false){
11489 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11494 onDestroy : function(){
11496 this.view.setStore(null);
11497 this.view.el.removeAllListeners();
11498 this.view.el.remove();
11499 this.view.purgeListeners();
11502 this.list.dom.innerHTML = '';
11506 this.store.un('beforeload', this.onBeforeLoad, this);
11507 this.store.un('load', this.onLoad, this);
11508 this.store.un('loadexception', this.onLoadException, this);
11510 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11514 fireKey : function(e){
11515 if(e.isNavKeyPress() && !this.list.isVisible()){
11516 this.fireEvent("specialkey", this, e);
11521 onResize: function(w, h){
11522 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11524 // if(typeof w != 'number'){
11525 // // we do not handle it!?!?
11528 // var tw = this.trigger.getWidth();
11529 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11530 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11532 // this.inputEl().setWidth( this.adjustWidth('input', x));
11534 // //this.trigger.setStyle('left', x+'px');
11536 // if(this.list && this.listWidth === undefined){
11537 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11538 // this.list.setWidth(lw);
11539 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11547 * Allow or prevent the user from directly editing the field text. If false is passed,
11548 * the user will only be able to select from the items defined in the dropdown list. This method
11549 * is the runtime equivalent of setting the 'editable' config option at config time.
11550 * @param {Boolean} value True to allow the user to directly edit the field text
11552 setEditable : function(value){
11553 if(value == this.editable){
11556 this.editable = value;
11558 this.inputEl().dom.setAttribute('readOnly', true);
11559 this.inputEl().on('mousedown', this.onTriggerClick, this);
11560 this.inputEl().addClass('x-combo-noedit');
11562 this.inputEl().dom.setAttribute('readOnly', false);
11563 this.inputEl().un('mousedown', this.onTriggerClick, this);
11564 this.inputEl().removeClass('x-combo-noedit');
11570 onBeforeLoad : function(combo,opts){
11571 if(!this.hasFocus){
11575 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11577 this.restrictHeight();
11578 this.selectedIndex = -1;
11582 onLoad : function(){
11584 this.hasQuery = false;
11586 if(!this.hasFocus){
11590 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11591 this.loading.hide();
11594 if(this.store.getCount() > 0){
11596 this.restrictHeight();
11597 if(this.lastQuery == this.allQuery){
11598 if(this.editable && !this.tickable){
11599 this.inputEl().dom.select();
11603 !this.selectByValue(this.value, true) &&
11606 !this.store.lastOptions ||
11607 typeof(this.store.lastOptions.add) == 'undefined' ||
11608 this.store.lastOptions.add != true
11611 this.select(0, true);
11614 if(this.autoFocus){
11617 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11618 this.taTask.delay(this.typeAheadDelay);
11622 this.onEmptyResults();
11628 onLoadException : function()
11630 this.hasQuery = false;
11632 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11633 this.loading.hide();
11636 if(this.tickable && this.editable){
11642 Roo.log(this.store.reader.jsonData);
11643 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11645 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11651 onTypeAhead : function(){
11652 if(this.store.getCount() > 0){
11653 var r = this.store.getAt(0);
11654 var newValue = r.data[this.displayField];
11655 var len = newValue.length;
11656 var selStart = this.getRawValue().length;
11658 if(selStart != len){
11659 this.setRawValue(newValue);
11660 this.selectText(selStart, newValue.length);
11666 onSelect : function(record, index){
11668 if(this.fireEvent('beforeselect', this, record, index) !== false){
11670 this.setFromData(index > -1 ? record.data : false);
11673 this.fireEvent('select', this, record, index);
11678 * Returns the currently selected field value or empty string if no value is set.
11679 * @return {String} value The selected value
11681 getValue : function(){
11684 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11687 if(this.valueField){
11688 return typeof this.value != 'undefined' ? this.value : '';
11690 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11695 * Clears any text/value currently set in the field
11697 clearValue : function(){
11698 if(this.hiddenField){
11699 this.hiddenField.dom.value = '';
11702 this.setRawValue('');
11703 this.lastSelectionText = '';
11704 this.lastData = false;
11709 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11710 * will be displayed in the field. If the value does not match the data value of an existing item,
11711 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11712 * Otherwise the field will be blank (although the value will still be set).
11713 * @param {String} value The value to match
11715 setValue : function(v){
11722 if(this.valueField){
11723 var r = this.findRecord(this.valueField, v);
11725 text = r.data[this.displayField];
11726 }else if(this.valueNotFoundText !== undefined){
11727 text = this.valueNotFoundText;
11730 this.lastSelectionText = text;
11731 if(this.hiddenField){
11732 this.hiddenField.dom.value = v;
11734 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11738 * @property {Object} the last set data for the element
11743 * Sets the value of the field based on a object which is related to the record format for the store.
11744 * @param {Object} value the value to set as. or false on reset?
11746 setFromData : function(o){
11753 var dv = ''; // display value
11754 var vv = ''; // value value..
11756 if (this.displayField) {
11757 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11759 // this is an error condition!!!
11760 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11763 if(this.valueField){
11764 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11767 if(this.hiddenField){
11768 this.hiddenField.dom.value = vv;
11770 this.lastSelectionText = dv;
11771 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11775 // no hidden field.. - we store the value in 'value', but still display
11776 // display field!!!!
11777 this.lastSelectionText = dv;
11778 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11784 reset : function(){
11785 // overridden so that last data is reset..
11792 this.setValue(this.originalValue);
11793 this.clearInvalid();
11794 this.lastData = false;
11796 this.view.clearSelections();
11800 findRecord : function(prop, value){
11802 if(this.store.getCount() > 0){
11803 this.store.each(function(r){
11804 if(r.data[prop] == value){
11814 getName: function()
11816 // returns hidden if it's set..
11817 if (!this.rendered) {return ''};
11818 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11822 onViewMove : function(e, t){
11823 this.inKeyMode = false;
11827 onViewOver : function(e, t){
11828 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11831 var item = this.view.findItemFromChild(t);
11834 var index = this.view.indexOf(item);
11835 this.select(index, false);
11840 onViewClick : function(view, doFocus, el, e)
11842 var index = this.view.getSelectedIndexes()[0];
11844 var r = this.store.getAt(index);
11848 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11855 Roo.each(this.tickItems, function(v,k){
11857 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11858 _this.tickItems.splice(k, 1);
11860 if(typeof(e) == 'undefined' && view == false){
11861 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11873 this.tickItems.push(r.data);
11875 if(typeof(e) == 'undefined' && view == false){
11876 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11883 this.onSelect(r, index);
11885 if(doFocus !== false && !this.blockFocus){
11886 this.inputEl().focus();
11891 restrictHeight : function(){
11892 //this.innerList.dom.style.height = '';
11893 //var inner = this.innerList.dom;
11894 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11895 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11896 //this.list.beginUpdate();
11897 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11898 this.list.alignTo(this.inputEl(), this.listAlign);
11899 this.list.alignTo(this.inputEl(), this.listAlign);
11900 //this.list.endUpdate();
11904 onEmptyResults : function(){
11906 if(this.tickable && this.editable){
11907 this.restrictHeight();
11915 * Returns true if the dropdown list is expanded, else false.
11917 isExpanded : function(){
11918 return this.list.isVisible();
11922 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11923 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11924 * @param {String} value The data value of the item to select
11925 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11926 * selected item if it is not currently in view (defaults to true)
11927 * @return {Boolean} True if the value matched an item in the list, else false
11929 selectByValue : function(v, scrollIntoView){
11930 if(v !== undefined && v !== null){
11931 var r = this.findRecord(this.valueField || this.displayField, v);
11933 this.select(this.store.indexOf(r), scrollIntoView);
11941 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11942 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11943 * @param {Number} index The zero-based index of the list item to select
11944 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11945 * selected item if it is not currently in view (defaults to true)
11947 select : function(index, scrollIntoView){
11948 this.selectedIndex = index;
11949 this.view.select(index);
11950 if(scrollIntoView !== false){
11951 var el = this.view.getNode(index);
11953 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11956 this.list.scrollChildIntoView(el, false);
11962 selectNext : function(){
11963 var ct = this.store.getCount();
11965 if(this.selectedIndex == -1){
11967 }else if(this.selectedIndex < ct-1){
11968 this.select(this.selectedIndex+1);
11974 selectPrev : function(){
11975 var ct = this.store.getCount();
11977 if(this.selectedIndex == -1){
11979 }else if(this.selectedIndex != 0){
11980 this.select(this.selectedIndex-1);
11986 onKeyUp : function(e){
11987 if(this.editable !== false && !e.isSpecialKey()){
11988 this.lastKey = e.getKey();
11989 this.dqTask.delay(this.queryDelay);
11994 validateBlur : function(){
11995 return !this.list || !this.list.isVisible();
11999 initQuery : function(){
12001 var v = this.getRawValue();
12003 if(this.tickable && this.editable){
12004 v = this.tickableInputEl().getValue();
12011 doForce : function(){
12012 if(this.inputEl().dom.value.length > 0){
12013 this.inputEl().dom.value =
12014 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12020 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12021 * query allowing the query action to be canceled if needed.
12022 * @param {String} query The SQL query to execute
12023 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12024 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12025 * saved in the current store (defaults to false)
12027 doQuery : function(q, forceAll){
12029 if(q === undefined || q === null){
12034 forceAll: forceAll,
12038 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12043 forceAll = qe.forceAll;
12044 if(forceAll === true || (q.length >= this.minChars)){
12046 this.hasQuery = true;
12048 if(this.lastQuery != q || this.alwaysQuery){
12049 this.lastQuery = q;
12050 if(this.mode == 'local'){
12051 this.selectedIndex = -1;
12053 this.store.clearFilter();
12055 this.store.filter(this.displayField, q);
12060 this.store.baseParams[this.queryParam] = q;
12062 var options = {params : this.getParams(q)};
12065 options.add = true;
12066 options.params.start = this.page * this.pageSize;
12069 this.store.load(options);
12072 * this code will make the page width larger, at the beginning, the list not align correctly,
12073 * we should expand the list on onLoad
12074 * so command out it
12079 this.selectedIndex = -1;
12084 this.loadNext = false;
12088 getParams : function(q){
12090 //p[this.queryParam] = q;
12094 p.limit = this.pageSize;
12100 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12102 collapse : function(){
12103 if(!this.isExpanded()){
12110 this.hasFocus = false;
12112 this.cancelBtn.hide();
12113 this.trigger.show();
12116 this.tickableInputEl().dom.value = '';
12117 this.tickableInputEl().blur();
12122 Roo.get(document).un('mousedown', this.collapseIf, this);
12123 Roo.get(document).un('mousewheel', this.collapseIf, this);
12124 if (!this.editable) {
12125 Roo.get(document).un('keydown', this.listKeyPress, this);
12127 this.fireEvent('collapse', this);
12131 collapseIf : function(e){
12132 var in_combo = e.within(this.el);
12133 var in_list = e.within(this.list);
12134 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12136 if (in_combo || in_list || is_list) {
12137 //e.stopPropagation();
12142 this.onTickableFooterButtonClick(e, false, false);
12150 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12152 expand : function(){
12154 if(this.isExpanded() || !this.hasFocus){
12158 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12159 this.list.setWidth(lw);
12166 this.restrictHeight();
12170 this.tickItems = Roo.apply([], this.item);
12173 this.cancelBtn.show();
12174 this.trigger.hide();
12177 this.tickableInputEl().focus();
12182 Roo.get(document).on('mousedown', this.collapseIf, this);
12183 Roo.get(document).on('mousewheel', this.collapseIf, this);
12184 if (!this.editable) {
12185 Roo.get(document).on('keydown', this.listKeyPress, this);
12188 this.fireEvent('expand', this);
12192 // Implements the default empty TriggerField.onTriggerClick function
12193 onTriggerClick : function(e)
12195 Roo.log('trigger click');
12197 if(this.disabled || !this.triggerList){
12202 this.loadNext = false;
12204 if(this.isExpanded()){
12206 if (!this.blockFocus) {
12207 this.inputEl().focus();
12211 this.hasFocus = true;
12212 if(this.triggerAction == 'all') {
12213 this.doQuery(this.allQuery, true);
12215 this.doQuery(this.getRawValue());
12217 if (!this.blockFocus) {
12218 this.inputEl().focus();
12223 onTickableTriggerClick : function(e)
12230 this.loadNext = false;
12231 this.hasFocus = true;
12233 if(this.triggerAction == 'all') {
12234 this.doQuery(this.allQuery, true);
12236 this.doQuery(this.getRawValue());
12240 onSearchFieldClick : function(e)
12242 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12243 this.onTickableFooterButtonClick(e, false, false);
12247 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12252 this.loadNext = false;
12253 this.hasFocus = true;
12255 if(this.triggerAction == 'all') {
12256 this.doQuery(this.allQuery, true);
12258 this.doQuery(this.getRawValue());
12262 listKeyPress : function(e)
12264 //Roo.log('listkeypress');
12265 // scroll to first matching element based on key pres..
12266 if (e.isSpecialKey()) {
12269 var k = String.fromCharCode(e.getKey()).toUpperCase();
12272 var csel = this.view.getSelectedNodes();
12273 var cselitem = false;
12275 var ix = this.view.indexOf(csel[0]);
12276 cselitem = this.store.getAt(ix);
12277 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12283 this.store.each(function(v) {
12285 // start at existing selection.
12286 if (cselitem.id == v.id) {
12292 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12293 match = this.store.indexOf(v);
12299 if (match === false) {
12300 return true; // no more action?
12303 this.view.select(match);
12304 var sn = Roo.get(this.view.getSelectedNodes()[0])
12305 sn.scrollIntoView(sn.dom.parentNode, false);
12308 onViewScroll : function(e, t){
12310 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){
12314 this.hasQuery = true;
12316 this.loading = this.list.select('.loading', true).first();
12318 if(this.loading === null){
12319 this.list.createChild({
12321 cls: 'loading select2-more-results select2-active',
12322 html: 'Loading more results...'
12325 this.loading = this.list.select('.loading', true).first();
12327 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12329 this.loading.hide();
12332 this.loading.show();
12337 this.loadNext = true;
12339 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12344 addItem : function(o)
12346 var dv = ''; // display value
12348 if (this.displayField) {
12349 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12351 // this is an error condition!!!
12352 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12359 var choice = this.choices.createChild({
12361 cls: 'select2-search-choice',
12370 cls: 'select2-search-choice-close',
12375 }, this.searchField);
12377 var close = choice.select('a.select2-search-choice-close', true).first()
12379 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12387 this.inputEl().dom.value = '';
12392 onRemoveItem : function(e, _self, o)
12394 e.preventDefault();
12396 this.lastItem = Roo.apply([], this.item);
12398 var index = this.item.indexOf(o.data) * 1;
12401 Roo.log('not this item?!');
12405 this.item.splice(index, 1);
12410 this.fireEvent('remove', this, e);
12416 syncValue : function()
12418 if(!this.item.length){
12425 Roo.each(this.item, function(i){
12426 if(_this.valueField){
12427 value.push(i[_this.valueField]);
12434 this.value = value.join(',');
12436 if(this.hiddenField){
12437 this.hiddenField.dom.value = this.value;
12441 clearItem : function()
12443 if(!this.multiple){
12449 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12458 inputEl: function ()
12461 return this.searchField;
12463 return this.el.select('input.form-control',true).first();
12467 onTickableFooterButtonClick : function(e, btn, el)
12469 e.preventDefault();
12471 this.lastItem = Roo.apply([], this.item);
12473 if(btn && btn.name == 'cancel'){
12474 this.tickItems = Roo.apply([], this.item);
12483 Roo.each(this.tickItems, function(o){
12491 validate : function()
12493 var v = this.getRawValue();
12496 v = this.getValue();
12499 if(this.disabled || this.allowBlank || v.length){
12504 this.markInvalid();
12508 tickableInputEl : function()
12510 if(!this.tickable || !this.editable){
12511 return this.inputEl();
12514 return this.inputEl().select('.select2-search-field-input', true).first();
12520 * @cfg {Boolean} grow
12524 * @cfg {Number} growMin
12528 * @cfg {Number} growMax
12538 * Ext JS Library 1.1.1
12539 * Copyright(c) 2006-2007, Ext JS, LLC.
12541 * Originally Released Under LGPL - original licence link has changed is not relivant.
12544 * <script type="text/javascript">
12549 * @extends Roo.util.Observable
12550 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12551 * This class also supports single and multi selection modes. <br>
12552 * Create a data model bound view:
12554 var store = new Roo.data.Store(...);
12556 var view = new Roo.View({
12558 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12560 singleSelect: true,
12561 selectedClass: "ydataview-selected",
12565 // listen for node click?
12566 view.on("click", function(vw, index, node, e){
12567 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12571 dataModel.load("foobar.xml");
12573 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12575 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12576 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12578 * Note: old style constructor is still suported (container, template, config)
12581 * Create a new View
12582 * @param {Object} config The config object
12585 Roo.View = function(config, depreciated_tpl, depreciated_config){
12587 this.parent = false;
12589 if (typeof(depreciated_tpl) == 'undefined') {
12590 // new way.. - universal constructor.
12591 Roo.apply(this, config);
12592 this.el = Roo.get(this.el);
12595 this.el = Roo.get(config);
12596 this.tpl = depreciated_tpl;
12597 Roo.apply(this, depreciated_config);
12599 this.wrapEl = this.el.wrap().wrap();
12600 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12603 if(typeof(this.tpl) == "string"){
12604 this.tpl = new Roo.Template(this.tpl);
12606 // support xtype ctors..
12607 this.tpl = new Roo.factory(this.tpl, Roo);
12611 this.tpl.compile();
12616 * @event beforeclick
12617 * Fires before a click is processed. Returns false to cancel the default action.
12618 * @param {Roo.View} this
12619 * @param {Number} index The index of the target node
12620 * @param {HTMLElement} node The target node
12621 * @param {Roo.EventObject} e The raw event object
12623 "beforeclick" : true,
12626 * Fires when a template node is clicked.
12627 * @param {Roo.View} this
12628 * @param {Number} index The index of the target node
12629 * @param {HTMLElement} node The target node
12630 * @param {Roo.EventObject} e The raw event object
12635 * Fires when a template node is double clicked.
12636 * @param {Roo.View} this
12637 * @param {Number} index The index of the target node
12638 * @param {HTMLElement} node The target node
12639 * @param {Roo.EventObject} e The raw event object
12643 * @event contextmenu
12644 * Fires when a template node is right clicked.
12645 * @param {Roo.View} this
12646 * @param {Number} index The index of the target node
12647 * @param {HTMLElement} node The target node
12648 * @param {Roo.EventObject} e The raw event object
12650 "contextmenu" : true,
12652 * @event selectionchange
12653 * Fires when the selected nodes change.
12654 * @param {Roo.View} this
12655 * @param {Array} selections Array of the selected nodes
12657 "selectionchange" : true,
12660 * @event beforeselect
12661 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12662 * @param {Roo.View} this
12663 * @param {HTMLElement} node The node to be selected
12664 * @param {Array} selections Array of currently selected nodes
12666 "beforeselect" : true,
12668 * @event preparedata
12669 * Fires on every row to render, to allow you to change the data.
12670 * @param {Roo.View} this
12671 * @param {Object} data to be rendered (change this)
12673 "preparedata" : true
12681 "click": this.onClick,
12682 "dblclick": this.onDblClick,
12683 "contextmenu": this.onContextMenu,
12687 this.selections = [];
12689 this.cmp = new Roo.CompositeElementLite([]);
12691 this.store = Roo.factory(this.store, Roo.data);
12692 this.setStore(this.store, true);
12695 if ( this.footer && this.footer.xtype) {
12697 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12699 this.footer.dataSource = this.store
12700 this.footer.container = fctr;
12701 this.footer = Roo.factory(this.footer, Roo);
12702 fctr.insertFirst(this.el);
12704 // this is a bit insane - as the paging toolbar seems to detach the el..
12705 // dom.parentNode.parentNode.parentNode
12706 // they get detached?
12710 Roo.View.superclass.constructor.call(this);
12715 Roo.extend(Roo.View, Roo.util.Observable, {
12718 * @cfg {Roo.data.Store} store Data store to load data from.
12723 * @cfg {String|Roo.Element} el The container element.
12728 * @cfg {String|Roo.Template} tpl The template used by this View
12732 * @cfg {String} dataName the named area of the template to use as the data area
12733 * Works with domtemplates roo-name="name"
12737 * @cfg {String} selectedClass The css class to add to selected nodes
12739 selectedClass : "x-view-selected",
12741 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12746 * @cfg {String} text to display on mask (default Loading)
12750 * @cfg {Boolean} multiSelect Allow multiple selection
12752 multiSelect : false,
12754 * @cfg {Boolean} singleSelect Allow single selection
12756 singleSelect: false,
12759 * @cfg {Boolean} toggleSelect - selecting
12761 toggleSelect : false,
12764 * @cfg {Boolean} tickable - selecting
12769 * Returns the element this view is bound to.
12770 * @return {Roo.Element}
12772 getEl : function(){
12773 return this.wrapEl;
12779 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12781 refresh : function(){
12782 //Roo.log('refresh');
12785 // if we are using something like 'domtemplate', then
12786 // the what gets used is:
12787 // t.applySubtemplate(NAME, data, wrapping data..)
12788 // the outer template then get' applied with
12789 // the store 'extra data'
12790 // and the body get's added to the
12791 // roo-name="data" node?
12792 // <span class='roo-tpl-{name}'></span> ?????
12796 this.clearSelections();
12797 this.el.update("");
12799 var records = this.store.getRange();
12800 if(records.length < 1) {
12802 // is this valid?? = should it render a template??
12804 this.el.update(this.emptyText);
12808 if (this.dataName) {
12809 this.el.update(t.apply(this.store.meta)); //????
12810 el = this.el.child('.roo-tpl-' + this.dataName);
12813 for(var i = 0, len = records.length; i < len; i++){
12814 var data = this.prepareData(records[i].data, i, records[i]);
12815 this.fireEvent("preparedata", this, data, i, records[i]);
12817 var d = Roo.apply({}, data);
12820 Roo.apply(d, {'roo-id' : Roo.id()});
12824 Roo.each(this.parent.item, function(item){
12825 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12828 Roo.apply(d, {'roo-data-checked' : 'checked'});
12832 html[html.length] = Roo.util.Format.trim(
12834 t.applySubtemplate(this.dataName, d, this.store.meta) :
12841 el.update(html.join(""));
12842 this.nodes = el.dom.childNodes;
12843 this.updateIndexes(0);
12848 * Function to override to reformat the data that is sent to
12849 * the template for each node.
12850 * DEPRICATED - use the preparedata event handler.
12851 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12852 * a JSON object for an UpdateManager bound view).
12854 prepareData : function(data, index, record)
12856 this.fireEvent("preparedata", this, data, index, record);
12860 onUpdate : function(ds, record){
12861 // Roo.log('on update');
12862 this.clearSelections();
12863 var index = this.store.indexOf(record);
12864 var n = this.nodes[index];
12865 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12866 n.parentNode.removeChild(n);
12867 this.updateIndexes(index, index);
12873 onAdd : function(ds, records, index)
12875 //Roo.log(['on Add', ds, records, index] );
12876 this.clearSelections();
12877 if(this.nodes.length == 0){
12881 var n = this.nodes[index];
12882 for(var i = 0, len = records.length; i < len; i++){
12883 var d = this.prepareData(records[i].data, i, records[i]);
12885 this.tpl.insertBefore(n, d);
12888 this.tpl.append(this.el, d);
12891 this.updateIndexes(index);
12894 onRemove : function(ds, record, index){
12895 // Roo.log('onRemove');
12896 this.clearSelections();
12897 var el = this.dataName ?
12898 this.el.child('.roo-tpl-' + this.dataName) :
12901 el.dom.removeChild(this.nodes[index]);
12902 this.updateIndexes(index);
12906 * Refresh an individual node.
12907 * @param {Number} index
12909 refreshNode : function(index){
12910 this.onUpdate(this.store, this.store.getAt(index));
12913 updateIndexes : function(startIndex, endIndex){
12914 var ns = this.nodes;
12915 startIndex = startIndex || 0;
12916 endIndex = endIndex || ns.length - 1;
12917 for(var i = startIndex; i <= endIndex; i++){
12918 ns[i].nodeIndex = i;
12923 * Changes the data store this view uses and refresh the view.
12924 * @param {Store} store
12926 setStore : function(store, initial){
12927 if(!initial && this.store){
12928 this.store.un("datachanged", this.refresh);
12929 this.store.un("add", this.onAdd);
12930 this.store.un("remove", this.onRemove);
12931 this.store.un("update", this.onUpdate);
12932 this.store.un("clear", this.refresh);
12933 this.store.un("beforeload", this.onBeforeLoad);
12934 this.store.un("load", this.onLoad);
12935 this.store.un("loadexception", this.onLoad);
12939 store.on("datachanged", this.refresh, this);
12940 store.on("add", this.onAdd, this);
12941 store.on("remove", this.onRemove, this);
12942 store.on("update", this.onUpdate, this);
12943 store.on("clear", this.refresh, this);
12944 store.on("beforeload", this.onBeforeLoad, this);
12945 store.on("load", this.onLoad, this);
12946 store.on("loadexception", this.onLoad, this);
12954 * onbeforeLoad - masks the loading area.
12957 onBeforeLoad : function(store,opts)
12959 //Roo.log('onBeforeLoad');
12961 this.el.update("");
12963 this.el.mask(this.mask ? this.mask : "Loading" );
12965 onLoad : function ()
12972 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12973 * @param {HTMLElement} node
12974 * @return {HTMLElement} The template node
12976 findItemFromChild : function(node){
12977 var el = this.dataName ?
12978 this.el.child('.roo-tpl-' + this.dataName,true) :
12981 if(!node || node.parentNode == el){
12984 var p = node.parentNode;
12985 while(p && p != el){
12986 if(p.parentNode == el){
12995 onClick : function(e){
12996 var item = this.findItemFromChild(e.getTarget());
12998 var index = this.indexOf(item);
12999 if(this.onItemClick(item, index, e) !== false){
13000 this.fireEvent("click", this, index, item, e);
13003 this.clearSelections();
13008 onContextMenu : function(e){
13009 var item = this.findItemFromChild(e.getTarget());
13011 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13016 onDblClick : function(e){
13017 var item = this.findItemFromChild(e.getTarget());
13019 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13023 onItemClick : function(item, index, e)
13025 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13028 if (this.toggleSelect) {
13029 var m = this.isSelected(item) ? 'unselect' : 'select';
13032 _t[m](item, true, false);
13035 if(this.multiSelect || this.singleSelect){
13036 if(this.multiSelect && e.shiftKey && this.lastSelection){
13037 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13039 this.select(item, this.multiSelect && e.ctrlKey);
13040 this.lastSelection = item;
13043 if(!this.tickable){
13044 e.preventDefault();
13052 * Get the number of selected nodes.
13055 getSelectionCount : function(){
13056 return this.selections.length;
13060 * Get the currently selected nodes.
13061 * @return {Array} An array of HTMLElements
13063 getSelectedNodes : function(){
13064 return this.selections;
13068 * Get the indexes of the selected nodes.
13071 getSelectedIndexes : function(){
13072 var indexes = [], s = this.selections;
13073 for(var i = 0, len = s.length; i < len; i++){
13074 indexes.push(s[i].nodeIndex);
13080 * Clear all selections
13081 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13083 clearSelections : function(suppressEvent){
13084 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13085 this.cmp.elements = this.selections;
13086 this.cmp.removeClass(this.selectedClass);
13087 this.selections = [];
13088 if(!suppressEvent){
13089 this.fireEvent("selectionchange", this, this.selections);
13095 * Returns true if the passed node is selected
13096 * @param {HTMLElement/Number} node The node or node index
13097 * @return {Boolean}
13099 isSelected : function(node){
13100 var s = this.selections;
13104 node = this.getNode(node);
13105 return s.indexOf(node) !== -1;
13110 * @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
13111 * @param {Boolean} keepExisting (optional) true to keep existing selections
13112 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13114 select : function(nodeInfo, keepExisting, suppressEvent){
13115 if(nodeInfo instanceof Array){
13117 this.clearSelections(true);
13119 for(var i = 0, len = nodeInfo.length; i < len; i++){
13120 this.select(nodeInfo[i], true, true);
13124 var node = this.getNode(nodeInfo);
13125 if(!node || this.isSelected(node)){
13126 return; // already selected.
13129 this.clearSelections(true);
13132 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13133 Roo.fly(node).addClass(this.selectedClass);
13134 this.selections.push(node);
13135 if(!suppressEvent){
13136 this.fireEvent("selectionchange", this, this.selections);
13144 * @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
13145 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13146 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13148 unselect : function(nodeInfo, keepExisting, suppressEvent)
13150 if(nodeInfo instanceof Array){
13151 Roo.each(this.selections, function(s) {
13152 this.unselect(s, nodeInfo);
13156 var node = this.getNode(nodeInfo);
13157 if(!node || !this.isSelected(node)){
13158 //Roo.log("not selected");
13159 return; // not selected.
13163 Roo.each(this.selections, function(s) {
13165 Roo.fly(node).removeClass(this.selectedClass);
13172 this.selections= ns;
13173 this.fireEvent("selectionchange", this, this.selections);
13177 * Gets a template node.
13178 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13179 * @return {HTMLElement} The node or null if it wasn't found
13181 getNode : function(nodeInfo){
13182 if(typeof nodeInfo == "string"){
13183 return document.getElementById(nodeInfo);
13184 }else if(typeof nodeInfo == "number"){
13185 return this.nodes[nodeInfo];
13191 * Gets a range template nodes.
13192 * @param {Number} startIndex
13193 * @param {Number} endIndex
13194 * @return {Array} An array of nodes
13196 getNodes : function(start, end){
13197 var ns = this.nodes;
13198 start = start || 0;
13199 end = typeof end == "undefined" ? ns.length - 1 : end;
13202 for(var i = start; i <= end; i++){
13206 for(var i = start; i >= end; i--){
13214 * Finds the index of the passed node
13215 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13216 * @return {Number} The index of the node or -1
13218 indexOf : function(node){
13219 node = this.getNode(node);
13220 if(typeof node.nodeIndex == "number"){
13221 return node.nodeIndex;
13223 var ns = this.nodes;
13224 for(var i = 0, len = ns.length; i < len; i++){
13235 * based on jquery fullcalendar
13239 Roo.bootstrap = Roo.bootstrap || {};
13241 * @class Roo.bootstrap.Calendar
13242 * @extends Roo.bootstrap.Component
13243 * Bootstrap Calendar class
13244 * @cfg {Boolean} loadMask (true|false) default false
13245 * @cfg {Object} header generate the user specific header of the calendar, default false
13248 * Create a new Container
13249 * @param {Object} config The config object
13254 Roo.bootstrap.Calendar = function(config){
13255 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13259 * Fires when a date is selected
13260 * @param {DatePicker} this
13261 * @param {Date} date The selected date
13265 * @event monthchange
13266 * Fires when the displayed month changes
13267 * @param {DatePicker} this
13268 * @param {Date} date The selected month
13270 'monthchange': true,
13272 * @event evententer
13273 * Fires when mouse over an event
13274 * @param {Calendar} this
13275 * @param {event} Event
13277 'evententer': true,
13279 * @event eventleave
13280 * Fires when the mouse leaves an
13281 * @param {Calendar} this
13284 'eventleave': true,
13286 * @event eventclick
13287 * Fires when the mouse click an
13288 * @param {Calendar} this
13297 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13300 * @cfg {Number} startDay
13301 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13309 getAutoCreate : function(){
13312 var fc_button = function(name, corner, style, content ) {
13313 return Roo.apply({},{
13315 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13317 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13320 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13331 style : 'width:100%',
13338 cls : 'fc-header-left',
13340 fc_button('prev', 'left', 'arrow', '‹' ),
13341 fc_button('next', 'right', 'arrow', '›' ),
13342 { tag: 'span', cls: 'fc-header-space' },
13343 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13351 cls : 'fc-header-center',
13355 cls: 'fc-header-title',
13358 html : 'month / year'
13366 cls : 'fc-header-right',
13368 /* fc_button('month', 'left', '', 'month' ),
13369 fc_button('week', '', '', 'week' ),
13370 fc_button('day', 'right', '', 'day' )
13382 header = this.header;
13385 var cal_heads = function() {
13387 // fixme - handle this.
13389 for (var i =0; i < Date.dayNames.length; i++) {
13390 var d = Date.dayNames[i];
13393 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13394 html : d.substring(0,3)
13398 ret[0].cls += ' fc-first';
13399 ret[6].cls += ' fc-last';
13402 var cal_cell = function(n) {
13405 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13410 cls: 'fc-day-number',
13414 cls: 'fc-day-content',
13418 style: 'position: relative;' // height: 17px;
13430 var cal_rows = function() {
13433 for (var r = 0; r < 6; r++) {
13440 for (var i =0; i < Date.dayNames.length; i++) {
13441 var d = Date.dayNames[i];
13442 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13445 row.cn[0].cls+=' fc-first';
13446 row.cn[0].cn[0].style = 'min-height:90px';
13447 row.cn[6].cls+=' fc-last';
13451 ret[0].cls += ' fc-first';
13452 ret[4].cls += ' fc-prev-last';
13453 ret[5].cls += ' fc-last';
13460 cls: 'fc-border-separate',
13461 style : 'width:100%',
13469 cls : 'fc-first fc-last',
13487 cls : 'fc-content',
13488 style : "position: relative;",
13491 cls : 'fc-view fc-view-month fc-grid',
13492 style : 'position: relative',
13493 unselectable : 'on',
13496 cls : 'fc-event-container',
13497 style : 'position:absolute;z-index:8;top:0;left:0;'
13515 initEvents : function()
13518 throw "can not find store for calendar";
13524 style: "text-align:center",
13528 style: "background-color:white;width:50%;margin:250 auto",
13532 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13543 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13545 var size = this.el.select('.fc-content', true).first().getSize();
13546 this.maskEl.setSize(size.width, size.height);
13547 this.maskEl.enableDisplayMode("block");
13548 if(!this.loadMask){
13549 this.maskEl.hide();
13552 this.store = Roo.factory(this.store, Roo.data);
13553 this.store.on('load', this.onLoad, this);
13554 this.store.on('beforeload', this.onBeforeLoad, this);
13558 this.cells = this.el.select('.fc-day',true);
13559 //Roo.log(this.cells);
13560 this.textNodes = this.el.query('.fc-day-number');
13561 this.cells.addClassOnOver('fc-state-hover');
13563 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13564 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13565 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13566 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13568 this.on('monthchange', this.onMonthChange, this);
13570 this.update(new Date().clearTime());
13573 resize : function() {
13574 var sz = this.el.getSize();
13576 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13577 this.el.select('.fc-day-content div',true).setHeight(34);
13582 showPrevMonth : function(e){
13583 this.update(this.activeDate.add("mo", -1));
13585 showToday : function(e){
13586 this.update(new Date().clearTime());
13589 showNextMonth : function(e){
13590 this.update(this.activeDate.add("mo", 1));
13594 showPrevYear : function(){
13595 this.update(this.activeDate.add("y", -1));
13599 showNextYear : function(){
13600 this.update(this.activeDate.add("y", 1));
13605 update : function(date)
13607 var vd = this.activeDate;
13608 this.activeDate = date;
13609 // if(vd && this.el){
13610 // var t = date.getTime();
13611 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13612 // Roo.log('using add remove');
13614 // this.fireEvent('monthchange', this, date);
13616 // this.cells.removeClass("fc-state-highlight");
13617 // this.cells.each(function(c){
13618 // if(c.dateValue == t){
13619 // c.addClass("fc-state-highlight");
13620 // setTimeout(function(){
13621 // try{c.dom.firstChild.focus();}catch(e){}
13631 var days = date.getDaysInMonth();
13633 var firstOfMonth = date.getFirstDateOfMonth();
13634 var startingPos = firstOfMonth.getDay()-this.startDay;
13636 if(startingPos < this.startDay){
13640 var pm = date.add(Date.MONTH, -1);
13641 var prevStart = pm.getDaysInMonth()-startingPos;
13643 this.cells = this.el.select('.fc-day',true);
13644 this.textNodes = this.el.query('.fc-day-number');
13645 this.cells.addClassOnOver('fc-state-hover');
13647 var cells = this.cells.elements;
13648 var textEls = this.textNodes;
13650 Roo.each(cells, function(cell){
13651 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13654 days += startingPos;
13656 // convert everything to numbers so it's fast
13657 var day = 86400000;
13658 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13661 //Roo.log(prevStart);
13663 var today = new Date().clearTime().getTime();
13664 var sel = date.clearTime().getTime();
13665 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13666 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13667 var ddMatch = this.disabledDatesRE;
13668 var ddText = this.disabledDatesText;
13669 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13670 var ddaysText = this.disabledDaysText;
13671 var format = this.format;
13673 var setCellClass = function(cal, cell){
13677 //Roo.log('set Cell Class');
13679 var t = d.getTime();
13683 cell.dateValue = t;
13685 cell.className += " fc-today";
13686 cell.className += " fc-state-highlight";
13687 cell.title = cal.todayText;
13690 // disable highlight in other month..
13691 //cell.className += " fc-state-highlight";
13696 cell.className = " fc-state-disabled";
13697 cell.title = cal.minText;
13701 cell.className = " fc-state-disabled";
13702 cell.title = cal.maxText;
13706 if(ddays.indexOf(d.getDay()) != -1){
13707 cell.title = ddaysText;
13708 cell.className = " fc-state-disabled";
13711 if(ddMatch && format){
13712 var fvalue = d.dateFormat(format);
13713 if(ddMatch.test(fvalue)){
13714 cell.title = ddText.replace("%0", fvalue);
13715 cell.className = " fc-state-disabled";
13719 if (!cell.initialClassName) {
13720 cell.initialClassName = cell.dom.className;
13723 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13728 for(; i < startingPos; i++) {
13729 textEls[i].innerHTML = (++prevStart);
13730 d.setDate(d.getDate()+1);
13732 cells[i].className = "fc-past fc-other-month";
13733 setCellClass(this, cells[i]);
13738 for(; i < days; i++){
13739 intDay = i - startingPos + 1;
13740 textEls[i].innerHTML = (intDay);
13741 d.setDate(d.getDate()+1);
13743 cells[i].className = ''; // "x-date-active";
13744 setCellClass(this, cells[i]);
13748 for(; i < 42; i++) {
13749 textEls[i].innerHTML = (++extraDays);
13750 d.setDate(d.getDate()+1);
13752 cells[i].className = "fc-future fc-other-month";
13753 setCellClass(this, cells[i]);
13756 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13758 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13760 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13761 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13763 if(totalRows != 6){
13764 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13765 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13768 this.fireEvent('monthchange', this, date);
13772 if(!this.internalRender){
13773 var main = this.el.dom.firstChild;
13774 var w = main.offsetWidth;
13775 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13776 Roo.fly(main).setWidth(w);
13777 this.internalRender = true;
13778 // opera does not respect the auto grow header center column
13779 // then, after it gets a width opera refuses to recalculate
13780 // without a second pass
13781 if(Roo.isOpera && !this.secondPass){
13782 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13783 this.secondPass = true;
13784 this.update.defer(10, this, [date]);
13791 findCell : function(dt) {
13792 dt = dt.clearTime().getTime();
13794 this.cells.each(function(c){
13795 //Roo.log("check " +c.dateValue + '?=' + dt);
13796 if(c.dateValue == dt){
13806 findCells : function(ev) {
13807 var s = ev.start.clone().clearTime().getTime();
13809 var e= ev.end.clone().clearTime().getTime();
13812 this.cells.each(function(c){
13813 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13815 if(c.dateValue > e){
13818 if(c.dateValue < s){
13827 // findBestRow: function(cells)
13831 // for (var i =0 ; i < cells.length;i++) {
13832 // ret = Math.max(cells[i].rows || 0,ret);
13839 addItem : function(ev)
13841 // look for vertical location slot in
13842 var cells = this.findCells(ev);
13844 // ev.row = this.findBestRow(cells);
13846 // work out the location.
13850 for(var i =0; i < cells.length; i++) {
13852 cells[i].row = cells[0].row;
13855 cells[i].row = cells[i].row + 1;
13865 if (crow.start.getY() == cells[i].getY()) {
13867 crow.end = cells[i];
13884 cells[0].events.push(ev);
13886 this.calevents.push(ev);
13889 clearEvents: function() {
13891 if(!this.calevents){
13895 Roo.each(this.cells.elements, function(c){
13901 Roo.each(this.calevents, function(e) {
13902 Roo.each(e.els, function(el) {
13903 el.un('mouseenter' ,this.onEventEnter, this);
13904 el.un('mouseleave' ,this.onEventLeave, this);
13909 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13915 renderEvents: function()
13919 this.cells.each(function(c) {
13928 if(c.row != c.events.length){
13929 r = 4 - (4 - (c.row - c.events.length));
13932 c.events = ev.slice(0, r);
13933 c.more = ev.slice(r);
13935 if(c.more.length && c.more.length == 1){
13936 c.events.push(c.more.pop());
13939 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13943 this.cells.each(function(c) {
13945 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13948 for (var e = 0; e < c.events.length; e++){
13949 var ev = c.events[e];
13950 var rows = ev.rows;
13952 for(var i = 0; i < rows.length; i++) {
13954 // how many rows should it span..
13957 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13958 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13960 unselectable : "on",
13963 cls: 'fc-event-inner',
13967 // cls: 'fc-event-time',
13968 // html : cells.length > 1 ? '' : ev.time
13972 cls: 'fc-event-title',
13973 html : String.format('{0}', ev.title)
13980 cls: 'ui-resizable-handle ui-resizable-e',
13981 html : '  '
13988 cfg.cls += ' fc-event-start';
13990 if ((i+1) == rows.length) {
13991 cfg.cls += ' fc-event-end';
13994 var ctr = _this.el.select('.fc-event-container',true).first();
13995 var cg = ctr.createChild(cfg);
13997 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13998 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14000 var r = (c.more.length) ? 1 : 0;
14001 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14002 cg.setWidth(ebox.right - sbox.x -2);
14004 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14005 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14006 cg.on('click', _this.onEventClick, _this, ev);
14017 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14018 style : 'position: absolute',
14019 unselectable : "on",
14022 cls: 'fc-event-inner',
14026 cls: 'fc-event-title',
14034 cls: 'ui-resizable-handle ui-resizable-e',
14035 html : '  '
14041 var ctr = _this.el.select('.fc-event-container',true).first();
14042 var cg = ctr.createChild(cfg);
14044 var sbox = c.select('.fc-day-content',true).first().getBox();
14045 var ebox = c.select('.fc-day-content',true).first().getBox();
14047 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14048 cg.setWidth(ebox.right - sbox.x -2);
14050 cg.on('click', _this.onMoreEventClick, _this, c.more);
14060 onEventEnter: function (e, el,event,d) {
14061 this.fireEvent('evententer', this, el, event);
14064 onEventLeave: function (e, el,event,d) {
14065 this.fireEvent('eventleave', this, el, event);
14068 onEventClick: function (e, el,event,d) {
14069 this.fireEvent('eventclick', this, el, event);
14072 onMonthChange: function () {
14076 onMoreEventClick: function(e, el, more)
14080 this.calpopover.placement = 'right';
14081 this.calpopover.setTitle('More');
14083 this.calpopover.setContent('');
14085 var ctr = this.calpopover.el.select('.popover-content', true).first();
14087 Roo.each(more, function(m){
14089 cls : 'fc-event-hori fc-event-draggable',
14092 var cg = ctr.createChild(cfg);
14094 cg.on('click', _this.onEventClick, _this, m);
14097 this.calpopover.show(el);
14102 onLoad: function ()
14104 this.calevents = [];
14107 if(this.store.getCount() > 0){
14108 this.store.data.each(function(d){
14111 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14112 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14113 time : d.data.start_time,
14114 title : d.data.title,
14115 description : d.data.description,
14116 venue : d.data.venue
14121 this.renderEvents();
14123 if(this.calevents.length && this.loadMask){
14124 this.maskEl.hide();
14128 onBeforeLoad: function()
14130 this.clearEvents();
14132 this.maskEl.show();
14146 * @class Roo.bootstrap.Popover
14147 * @extends Roo.bootstrap.Component
14148 * Bootstrap Popover class
14149 * @cfg {String} html contents of the popover (or false to use children..)
14150 * @cfg {String} title of popover (or false to hide)
14151 * @cfg {String} placement how it is placed
14152 * @cfg {String} trigger click || hover (or false to trigger manually)
14153 * @cfg {String} over what (parent or false to trigger manually.)
14154 * @cfg {Number} delay - delay before showing
14157 * Create a new Popover
14158 * @param {Object} config The config object
14161 Roo.bootstrap.Popover = function(config){
14162 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14165 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14167 title: 'Fill in a title',
14170 placement : 'right',
14171 trigger : 'hover', // hover
14177 can_build_overlaid : false,
14179 getChildContainer : function()
14181 return this.el.select('.popover-content',true).first();
14184 getAutoCreate : function(){
14185 Roo.log('make popover?');
14187 cls : 'popover roo-dynamic',
14188 style: 'display:block',
14194 cls : 'popover-inner',
14198 cls: 'popover-title',
14202 cls : 'popover-content',
14213 setTitle: function(str)
14215 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14217 setContent: function(str)
14219 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14221 // as it get's added to the bottom of the page.
14222 onRender : function(ct, position)
14224 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14226 var cfg = Roo.apply({}, this.getAutoCreate());
14230 cfg.cls += ' ' + this.cls;
14233 cfg.style = this.style;
14235 Roo.log("adding to ")
14236 this.el = Roo.get(document.body).createChild(cfg, position);
14242 initEvents : function()
14244 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14245 this.el.enableDisplayMode('block');
14247 if (this.over === false) {
14250 if (this.triggers === false) {
14253 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14254 var triggers = this.trigger ? this.trigger.split(' ') : [];
14255 Roo.each(triggers, function(trigger) {
14257 if (trigger == 'click') {
14258 on_el.on('click', this.toggle, this);
14259 } else if (trigger != 'manual') {
14260 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14261 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14263 on_el.on(eventIn ,this.enter, this);
14264 on_el.on(eventOut, this.leave, this);
14275 toggle : function () {
14276 this.hoverState == 'in' ? this.leave() : this.enter();
14279 enter : function () {
14282 clearTimeout(this.timeout);
14284 this.hoverState = 'in';
14286 if (!this.delay || !this.delay.show) {
14291 this.timeout = setTimeout(function () {
14292 if (_t.hoverState == 'in') {
14295 }, this.delay.show)
14297 leave : function() {
14298 clearTimeout(this.timeout);
14300 this.hoverState = 'out';
14302 if (!this.delay || !this.delay.hide) {
14307 this.timeout = setTimeout(function () {
14308 if (_t.hoverState == 'out') {
14311 }, this.delay.hide)
14314 show : function (on_el)
14317 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14320 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14321 if (this.html !== false) {
14322 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14324 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14325 if (!this.title.length) {
14326 this.el.select('.popover-title',true).hide();
14329 var placement = typeof this.placement == 'function' ?
14330 this.placement.call(this, this.el, on_el) :
14333 var autoToken = /\s?auto?\s?/i;
14334 var autoPlace = autoToken.test(placement);
14336 placement = placement.replace(autoToken, '') || 'top';
14340 //this.el.setXY([0,0]);
14342 this.el.dom.style.display='block';
14343 this.el.addClass(placement);
14345 //this.el.appendTo(on_el);
14347 var p = this.getPosition();
14348 var box = this.el.getBox();
14353 var align = Roo.bootstrap.Popover.alignment[placement];
14354 this.el.alignTo(on_el, align[0],align[1]);
14355 //var arrow = this.el.select('.arrow',true).first();
14356 //arrow.set(align[2],
14358 this.el.addClass('in');
14359 this.hoverState = null;
14361 if (this.el.hasClass('fade')) {
14368 this.el.setXY([0,0]);
14369 this.el.removeClass('in');
14376 Roo.bootstrap.Popover.alignment = {
14377 'left' : ['r-l', [-10,0], 'right'],
14378 'right' : ['l-r', [10,0], 'left'],
14379 'bottom' : ['t-b', [0,10], 'top'],
14380 'top' : [ 'b-t', [0,-10], 'bottom']
14391 * @class Roo.bootstrap.Progress
14392 * @extends Roo.bootstrap.Component
14393 * Bootstrap Progress class
14394 * @cfg {Boolean} striped striped of the progress bar
14395 * @cfg {Boolean} active animated of the progress bar
14399 * Create a new Progress
14400 * @param {Object} config The config object
14403 Roo.bootstrap.Progress = function(config){
14404 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14407 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14412 getAutoCreate : function(){
14420 cfg.cls += ' progress-striped';
14424 cfg.cls += ' active';
14443 * @class Roo.bootstrap.ProgressBar
14444 * @extends Roo.bootstrap.Component
14445 * Bootstrap ProgressBar class
14446 * @cfg {Number} aria_valuenow aria-value now
14447 * @cfg {Number} aria_valuemin aria-value min
14448 * @cfg {Number} aria_valuemax aria-value max
14449 * @cfg {String} label label for the progress bar
14450 * @cfg {String} panel (success | info | warning | danger )
14451 * @cfg {String} role role of the progress bar
14452 * @cfg {String} sr_only text
14456 * Create a new ProgressBar
14457 * @param {Object} config The config object
14460 Roo.bootstrap.ProgressBar = function(config){
14461 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14464 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14468 aria_valuemax : 100,
14474 getAutoCreate : function()
14479 cls: 'progress-bar',
14480 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14492 cfg.role = this.role;
14495 if(this.aria_valuenow){
14496 cfg['aria-valuenow'] = this.aria_valuenow;
14499 if(this.aria_valuemin){
14500 cfg['aria-valuemin'] = this.aria_valuemin;
14503 if(this.aria_valuemax){
14504 cfg['aria-valuemax'] = this.aria_valuemax;
14507 if(this.label && !this.sr_only){
14508 cfg.html = this.label;
14512 cfg.cls += ' progress-bar-' + this.panel;
14518 update : function(aria_valuenow)
14520 this.aria_valuenow = aria_valuenow;
14522 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14537 * @class Roo.bootstrap.TabGroup
14538 * @extends Roo.bootstrap.Column
14539 * Bootstrap Column class
14540 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14541 * @cfg {Boolean} carousel true to make the group behave like a carousel
14544 * Create a new TabGroup
14545 * @param {Object} config The config object
14548 Roo.bootstrap.TabGroup = function(config){
14549 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14551 this.navId = Roo.id();
14554 Roo.bootstrap.TabGroup.register(this);
14558 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14561 transition : false,
14563 getAutoCreate : function()
14565 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14567 cfg.cls += ' tab-content';
14569 if (this.carousel) {
14570 cfg.cls += ' carousel slide';
14572 cls : 'carousel-inner'
14579 getChildContainer : function()
14581 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14585 * register a Navigation item
14586 * @param {Roo.bootstrap.NavItem} the navitem to add
14588 register : function(item)
14590 this.tabs.push( item);
14591 item.navId = this.navId; // not really needed..
14595 getActivePanel : function()
14598 Roo.each(this.tabs, function(t) {
14608 getPanelByName : function(n)
14611 Roo.each(this.tabs, function(t) {
14612 if (t.tabId == n) {
14620 indexOfPanel : function(p)
14623 Roo.each(this.tabs, function(t,i) {
14624 if (t.tabId == p.tabId) {
14633 * show a specific panel
14634 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14635 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14637 showPanel : function (pan)
14640 if (typeof(pan) == 'number') {
14641 pan = this.tabs[pan];
14643 if (typeof(pan) == 'string') {
14644 pan = this.getPanelByName(pan);
14646 if (pan.tabId == this.getActivePanel().tabId) {
14649 var cur = this.getActivePanel();
14651 if (false === cur.fireEvent('beforedeactivate')) {
14655 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14657 this.transition = true;
14658 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14659 var lr = dir == 'next' ? 'left' : 'right';
14660 pan.el.addClass(dir); // or prev
14661 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14662 cur.el.addClass(lr); // or right
14663 pan.el.addClass(lr);
14666 cur.el.on('transitionend', function() {
14667 Roo.log("trans end?");
14669 pan.el.removeClass([lr,dir]);
14670 pan.setActive(true);
14672 cur.el.removeClass([lr]);
14673 cur.setActive(false);
14675 _this.transition = false;
14677 }, this, { single: true } );
14681 cur.setActive(false);
14682 pan.setActive(true);
14686 showPanelNext : function()
14688 var i = this.indexOfPanel(this.getActivePanel());
14689 if (i > this.tabs.length) {
14692 this.showPanel(this.tabs[i+1]);
14694 showPanelPrev : function()
14696 var i = this.indexOfPanel(this.getActivePanel());
14700 this.showPanel(this.tabs[i-1]);
14711 Roo.apply(Roo.bootstrap.TabGroup, {
14715 * register a Navigation Group
14716 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14718 register : function(navgrp)
14720 this.groups[navgrp.navId] = navgrp;
14724 * fetch a Navigation Group based on the navigation ID
14725 * if one does not exist , it will get created.
14726 * @param {string} the navgroup to add
14727 * @returns {Roo.bootstrap.NavGroup} the navgroup
14729 get: function(navId) {
14730 if (typeof(this.groups[navId]) == 'undefined') {
14731 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14733 return this.groups[navId] ;
14748 * @class Roo.bootstrap.TabPanel
14749 * @extends Roo.bootstrap.Component
14750 * Bootstrap TabPanel class
14751 * @cfg {Boolean} active panel active
14752 * @cfg {String} html panel content
14753 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14754 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14758 * Create a new TabPanel
14759 * @param {Object} config The config object
14762 Roo.bootstrap.TabPanel = function(config){
14763 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14767 * Fires when the active status changes
14768 * @param {Roo.bootstrap.TabPanel} this
14769 * @param {Boolean} state the new state
14774 * @event beforedeactivate
14775 * Fires before a tab is de-activated - can be used to do validation on a form.
14776 * @param {Roo.bootstrap.TabPanel} this
14777 * @return {Boolean} false if there is an error
14780 'beforedeactivate': true
14783 this.tabId = this.tabId || Roo.id();
14787 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14794 getAutoCreate : function(){
14797 // item is needed for carousel - not sure if it has any effect otherwise
14798 cls: 'tab-pane item',
14799 html: this.html || ''
14803 cfg.cls += ' active';
14807 cfg.tabId = this.tabId;
14814 initEvents: function()
14816 Roo.log('-------- init events on tab panel ---------');
14818 var p = this.parent();
14819 this.navId = this.navId || p.navId;
14821 if (typeof(this.navId) != 'undefined') {
14822 // not really needed.. but just in case.. parent should be a NavGroup.
14823 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14824 Roo.log(['register', tg, this]);
14830 onRender : function(ct, position)
14832 // Roo.log("Call onRender: " + this.xtype);
14834 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14842 setActive: function(state)
14844 Roo.log("panel - set active " + this.tabId + "=" + state);
14846 this.active = state;
14848 this.el.removeClass('active');
14850 } else if (!this.el.hasClass('active')) {
14851 this.el.addClass('active');
14853 this.fireEvent('changed', this, state);
14870 * @class Roo.bootstrap.DateField
14871 * @extends Roo.bootstrap.Input
14872 * Bootstrap DateField class
14873 * @cfg {Number} weekStart default 0
14874 * @cfg {String} viewMode default empty, (months|years)
14875 * @cfg {String} minViewMode default empty, (months|years)
14876 * @cfg {Number} startDate default -Infinity
14877 * @cfg {Number} endDate default Infinity
14878 * @cfg {Boolean} todayHighlight default false
14879 * @cfg {Boolean} todayBtn default false
14880 * @cfg {Boolean} calendarWeeks default false
14881 * @cfg {Object} daysOfWeekDisabled default empty
14882 * @cfg {Boolean} singleMode default false (true | false)
14884 * @cfg {Boolean} keyboardNavigation default true
14885 * @cfg {String} language default en
14888 * Create a new DateField
14889 * @param {Object} config The config object
14892 Roo.bootstrap.DateField = function(config){
14893 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14897 * Fires when this field show.
14898 * @param {Roo.bootstrap.DateField} this
14899 * @param {Mixed} date The date value
14904 * Fires when this field hide.
14905 * @param {Roo.bootstrap.DateField} this
14906 * @param {Mixed} date The date value
14911 * Fires when select a date.
14912 * @param {Roo.bootstrap.DateField} this
14913 * @param {Mixed} date The date value
14919 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14922 * @cfg {String} format
14923 * The default date format string which can be overriden for localization support. The format must be
14924 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14928 * @cfg {String} altFormats
14929 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14930 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14932 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14940 todayHighlight : false,
14946 keyboardNavigation: true,
14948 calendarWeeks: false,
14950 startDate: -Infinity,
14954 daysOfWeekDisabled: [],
14958 singleMode : false,
14960 UTCDate: function()
14962 return new Date(Date.UTC.apply(Date, arguments));
14965 UTCToday: function()
14967 var today = new Date();
14968 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14971 getDate: function() {
14972 var d = this.getUTCDate();
14973 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14976 getUTCDate: function() {
14980 setDate: function(d) {
14981 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14984 setUTCDate: function(d) {
14986 this.setValue(this.formatDate(this.date));
14989 onRender: function(ct, position)
14992 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14994 this.language = this.language || 'en';
14995 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14996 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14998 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14999 this.format = this.format || 'm/d/y';
15000 this.isInline = false;
15001 this.isInput = true;
15002 this.component = this.el.select('.add-on', true).first() || false;
15003 this.component = (this.component && this.component.length === 0) ? false : this.component;
15004 this.hasInput = this.component && this.inputEL().length;
15006 if (typeof(this.minViewMode === 'string')) {
15007 switch (this.minViewMode) {
15009 this.minViewMode = 1;
15012 this.minViewMode = 2;
15015 this.minViewMode = 0;
15020 if (typeof(this.viewMode === 'string')) {
15021 switch (this.viewMode) {
15034 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15036 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15038 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15040 this.picker().on('mousedown', this.onMousedown, this);
15041 this.picker().on('click', this.onClick, this);
15043 this.picker().addClass('datepicker-dropdown');
15045 this.startViewMode = this.viewMode;
15047 if(this.singleMode){
15048 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15049 v.setVisibilityMode(Roo.Element.DISPLAY)
15053 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15054 v.setStyle('width', '189px');
15058 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15059 if(!this.calendarWeeks){
15064 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15065 v.attr('colspan', function(i, val){
15066 return parseInt(val) + 1;
15071 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15073 this.setStartDate(this.startDate);
15074 this.setEndDate(this.endDate);
15076 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15083 if(this.isInline) {
15088 picker : function()
15090 return this.pickerEl;
15091 // return this.el.select('.datepicker', true).first();
15094 fillDow: function()
15096 var dowCnt = this.weekStart;
15105 if(this.calendarWeeks){
15113 while (dowCnt < this.weekStart + 7) {
15117 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15121 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15124 fillMonths: function()
15127 var months = this.picker().select('>.datepicker-months td', true).first();
15129 months.dom.innerHTML = '';
15135 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15138 months.createChild(month);
15145 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;
15147 if (this.date < this.startDate) {
15148 this.viewDate = new Date(this.startDate);
15149 } else if (this.date > this.endDate) {
15150 this.viewDate = new Date(this.endDate);
15152 this.viewDate = new Date(this.date);
15160 var d = new Date(this.viewDate),
15161 year = d.getUTCFullYear(),
15162 month = d.getUTCMonth(),
15163 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15164 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15165 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15166 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15167 currentDate = this.date && this.date.valueOf(),
15168 today = this.UTCToday();
15170 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15172 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15174 // this.picker.select('>tfoot th.today').
15175 // .text(dates[this.language].today)
15176 // .toggle(this.todayBtn !== false);
15178 this.updateNavArrows();
15181 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15183 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15185 prevMonth.setUTCDate(day);
15187 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15189 var nextMonth = new Date(prevMonth);
15191 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15193 nextMonth = nextMonth.valueOf();
15195 var fillMonths = false;
15197 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15199 while(prevMonth.valueOf() < nextMonth) {
15202 if (prevMonth.getUTCDay() === this.weekStart) {
15204 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15212 if(this.calendarWeeks){
15213 // ISO 8601: First week contains first thursday.
15214 // ISO also states week starts on Monday, but we can be more abstract here.
15216 // Start of current week: based on weekstart/current date
15217 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15218 // Thursday of this week
15219 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15220 // First Thursday of year, year from thursday
15221 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15222 // Calendar week: ms between thursdays, div ms per day, div 7 days
15223 calWeek = (th - yth) / 864e5 / 7 + 1;
15225 fillMonths.cn.push({
15233 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15235 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15238 if (this.todayHighlight &&
15239 prevMonth.getUTCFullYear() == today.getFullYear() &&
15240 prevMonth.getUTCMonth() == today.getMonth() &&
15241 prevMonth.getUTCDate() == today.getDate()) {
15242 clsName += ' today';
15245 if (currentDate && prevMonth.valueOf() === currentDate) {
15246 clsName += ' active';
15249 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15250 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15251 clsName += ' disabled';
15254 fillMonths.cn.push({
15256 cls: 'day ' + clsName,
15257 html: prevMonth.getDate()
15260 prevMonth.setDate(prevMonth.getDate()+1);
15263 var currentYear = this.date && this.date.getUTCFullYear();
15264 var currentMonth = this.date && this.date.getUTCMonth();
15266 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15268 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15269 v.removeClass('active');
15271 if(currentYear === year && k === currentMonth){
15272 v.addClass('active');
15275 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15276 v.addClass('disabled');
15282 year = parseInt(year/10, 10) * 10;
15284 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15286 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15289 for (var i = -1; i < 11; i++) {
15290 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15292 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15300 showMode: function(dir)
15303 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15306 Roo.each(this.picker().select('>div',true).elements, function(v){
15307 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15310 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15315 if(this.isInline) return;
15317 this.picker().removeClass(['bottom', 'top']);
15319 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15321 * place to the top of element!
15325 this.picker().addClass('top');
15326 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15331 this.picker().addClass('bottom');
15333 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15336 parseDate : function(value)
15338 if(!value || value instanceof Date){
15341 var v = Date.parseDate(value, this.format);
15342 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15343 v = Date.parseDate(value, 'Y-m-d');
15345 if(!v && this.altFormats){
15346 if(!this.altFormatsArray){
15347 this.altFormatsArray = this.altFormats.split("|");
15349 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15350 v = Date.parseDate(value, this.altFormatsArray[i]);
15356 formatDate : function(date, fmt)
15358 return (!date || !(date instanceof Date)) ?
15359 date : date.dateFormat(fmt || this.format);
15362 onFocus : function()
15364 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15368 onBlur : function()
15370 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15372 var d = this.inputEl().getValue();
15381 this.picker().show();
15385 this.fireEvent('show', this, this.date);
15390 if(this.isInline) return;
15391 this.picker().hide();
15392 this.viewMode = this.startViewMode;
15395 this.fireEvent('hide', this, this.date);
15399 onMousedown: function(e)
15401 e.stopPropagation();
15402 e.preventDefault();
15407 Roo.bootstrap.DateField.superclass.keyup.call(this);
15411 setValue: function(v)
15414 // v can be a string or a date..
15417 var d = new Date(this.parseDate(v) ).clearTime();
15419 if(isNaN(d.getTime())){
15420 this.date = this.viewDate = '';
15421 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15425 v = this.formatDate(d);
15427 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15429 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15433 this.fireEvent('select', this, this.date);
15437 getValue: function()
15439 return this.formatDate(this.date);
15442 fireKey: function(e)
15444 if (!this.picker().isVisible()){
15445 if (e.keyCode == 27) // allow escape to hide and re-show picker
15450 var dateChanged = false,
15452 newDate, newViewDate;
15457 e.preventDefault();
15461 if (!this.keyboardNavigation) break;
15462 dir = e.keyCode == 37 ? -1 : 1;
15465 newDate = this.moveYear(this.date, dir);
15466 newViewDate = this.moveYear(this.viewDate, dir);
15467 } else if (e.shiftKey){
15468 newDate = this.moveMonth(this.date, dir);
15469 newViewDate = this.moveMonth(this.viewDate, dir);
15471 newDate = new Date(this.date);
15472 newDate.setUTCDate(this.date.getUTCDate() + dir);
15473 newViewDate = new Date(this.viewDate);
15474 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15476 if (this.dateWithinRange(newDate)){
15477 this.date = newDate;
15478 this.viewDate = newViewDate;
15479 this.setValue(this.formatDate(this.date));
15481 e.preventDefault();
15482 dateChanged = true;
15487 if (!this.keyboardNavigation) break;
15488 dir = e.keyCode == 38 ? -1 : 1;
15490 newDate = this.moveYear(this.date, dir);
15491 newViewDate = this.moveYear(this.viewDate, dir);
15492 } else if (e.shiftKey){
15493 newDate = this.moveMonth(this.date, dir);
15494 newViewDate = this.moveMonth(this.viewDate, dir);
15496 newDate = new Date(this.date);
15497 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15498 newViewDate = new Date(this.viewDate);
15499 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15501 if (this.dateWithinRange(newDate)){
15502 this.date = newDate;
15503 this.viewDate = newViewDate;
15504 this.setValue(this.formatDate(this.date));
15506 e.preventDefault();
15507 dateChanged = true;
15511 this.setValue(this.formatDate(this.date));
15513 e.preventDefault();
15516 this.setValue(this.formatDate(this.date));
15530 onClick: function(e)
15532 e.stopPropagation();
15533 e.preventDefault();
15535 var target = e.getTarget();
15537 if(target.nodeName.toLowerCase() === 'i'){
15538 target = Roo.get(target).dom.parentNode;
15541 var nodeName = target.nodeName;
15542 var className = target.className;
15543 var html = target.innerHTML;
15544 //Roo.log(nodeName);
15546 switch(nodeName.toLowerCase()) {
15548 switch(className) {
15554 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15555 switch(this.viewMode){
15557 this.viewDate = this.moveMonth(this.viewDate, dir);
15561 this.viewDate = this.moveYear(this.viewDate, dir);
15567 var date = new Date();
15568 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15570 this.setValue(this.formatDate(this.date));
15577 if (className.indexOf('disabled') < 0) {
15578 this.viewDate.setUTCDate(1);
15579 if (className.indexOf('month') > -1) {
15580 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15582 var year = parseInt(html, 10) || 0;
15583 this.viewDate.setUTCFullYear(year);
15587 if(this.singleMode){
15588 this.setValue(this.formatDate(this.viewDate));
15599 //Roo.log(className);
15600 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15601 var day = parseInt(html, 10) || 1;
15602 var year = this.viewDate.getUTCFullYear(),
15603 month = this.viewDate.getUTCMonth();
15605 if (className.indexOf('old') > -1) {
15612 } else if (className.indexOf('new') > -1) {
15620 //Roo.log([year,month,day]);
15621 this.date = this.UTCDate(year, month, day,0,0,0,0);
15622 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15624 //Roo.log(this.formatDate(this.date));
15625 this.setValue(this.formatDate(this.date));
15632 setStartDate: function(startDate)
15634 this.startDate = startDate || -Infinity;
15635 if (this.startDate !== -Infinity) {
15636 this.startDate = this.parseDate(this.startDate);
15639 this.updateNavArrows();
15642 setEndDate: function(endDate)
15644 this.endDate = endDate || Infinity;
15645 if (this.endDate !== Infinity) {
15646 this.endDate = this.parseDate(this.endDate);
15649 this.updateNavArrows();
15652 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15654 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15655 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15656 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15658 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15659 return parseInt(d, 10);
15662 this.updateNavArrows();
15665 updateNavArrows: function()
15667 if(this.singleMode){
15671 var d = new Date(this.viewDate),
15672 year = d.getUTCFullYear(),
15673 month = d.getUTCMonth();
15675 Roo.each(this.picker().select('.prev', true).elements, function(v){
15677 switch (this.viewMode) {
15680 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15686 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15693 Roo.each(this.picker().select('.next', true).elements, function(v){
15695 switch (this.viewMode) {
15698 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15704 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15712 moveMonth: function(date, dir)
15714 if (!dir) return date;
15715 var new_date = new Date(date.valueOf()),
15716 day = new_date.getUTCDate(),
15717 month = new_date.getUTCMonth(),
15718 mag = Math.abs(dir),
15720 dir = dir > 0 ? 1 : -1;
15723 // If going back one month, make sure month is not current month
15724 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15726 return new_date.getUTCMonth() == month;
15728 // If going forward one month, make sure month is as expected
15729 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15731 return new_date.getUTCMonth() != new_month;
15733 new_month = month + dir;
15734 new_date.setUTCMonth(new_month);
15735 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15736 if (new_month < 0 || new_month > 11)
15737 new_month = (new_month + 12) % 12;
15739 // For magnitudes >1, move one month at a time...
15740 for (var i=0; i<mag; i++)
15741 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15742 new_date = this.moveMonth(new_date, dir);
15743 // ...then reset the day, keeping it in the new month
15744 new_month = new_date.getUTCMonth();
15745 new_date.setUTCDate(day);
15747 return new_month != new_date.getUTCMonth();
15750 // Common date-resetting loop -- if date is beyond end of month, make it
15753 new_date.setUTCDate(--day);
15754 new_date.setUTCMonth(new_month);
15759 moveYear: function(date, dir)
15761 return this.moveMonth(date, dir*12);
15764 dateWithinRange: function(date)
15766 return date >= this.startDate && date <= this.endDate;
15772 this.picker().remove();
15777 Roo.apply(Roo.bootstrap.DateField, {
15788 html: '<i class="fa fa-arrow-left"/>'
15798 html: '<i class="fa fa-arrow-right"/>'
15840 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15841 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15842 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15843 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15844 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15857 navFnc: 'FullYear',
15862 navFnc: 'FullYear',
15867 Roo.apply(Roo.bootstrap.DateField, {
15871 cls: 'datepicker dropdown-menu roo-dynamic',
15875 cls: 'datepicker-days',
15879 cls: 'table-condensed',
15881 Roo.bootstrap.DateField.head,
15885 Roo.bootstrap.DateField.footer
15892 cls: 'datepicker-months',
15896 cls: 'table-condensed',
15898 Roo.bootstrap.DateField.head,
15899 Roo.bootstrap.DateField.content,
15900 Roo.bootstrap.DateField.footer
15907 cls: 'datepicker-years',
15911 cls: 'table-condensed',
15913 Roo.bootstrap.DateField.head,
15914 Roo.bootstrap.DateField.content,
15915 Roo.bootstrap.DateField.footer
15934 * @class Roo.bootstrap.TimeField
15935 * @extends Roo.bootstrap.Input
15936 * Bootstrap DateField class
15940 * Create a new TimeField
15941 * @param {Object} config The config object
15944 Roo.bootstrap.TimeField = function(config){
15945 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15949 * Fires when this field show.
15950 * @param {Roo.bootstrap.DateField} thisthis
15951 * @param {Mixed} date The date value
15956 * Fires when this field hide.
15957 * @param {Roo.bootstrap.DateField} this
15958 * @param {Mixed} date The date value
15963 * Fires when select a date.
15964 * @param {Roo.bootstrap.DateField} this
15965 * @param {Mixed} date The date value
15971 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15974 * @cfg {String} format
15975 * The default time format string which can be overriden for localization support. The format must be
15976 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15980 onRender: function(ct, position)
15983 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15985 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15987 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15989 this.pop = this.picker().select('>.datepicker-time',true).first();
15990 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15992 this.picker().on('mousedown', this.onMousedown, this);
15993 this.picker().on('click', this.onClick, this);
15995 this.picker().addClass('datepicker-dropdown');
16000 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16001 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16002 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16003 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16004 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16005 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16009 fireKey: function(e){
16010 if (!this.picker().isVisible()){
16011 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16017 e.preventDefault();
16025 this.onTogglePeriod();
16028 this.onIncrementMinutes();
16031 this.onDecrementMinutes();
16040 onClick: function(e) {
16041 e.stopPropagation();
16042 e.preventDefault();
16045 picker : function()
16047 return this.el.select('.datepicker', true).first();
16050 fillTime: function()
16052 var time = this.pop.select('tbody', true).first();
16054 time.dom.innerHTML = '';
16069 cls: 'hours-up glyphicon glyphicon-chevron-up'
16089 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16110 cls: 'timepicker-hour',
16125 cls: 'timepicker-minute',
16140 cls: 'btn btn-primary period',
16162 cls: 'hours-down glyphicon glyphicon-chevron-down'
16182 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16200 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16207 var hours = this.time.getHours();
16208 var minutes = this.time.getMinutes();
16221 hours = hours - 12;
16225 hours = '0' + hours;
16229 minutes = '0' + minutes;
16232 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16233 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16234 this.pop.select('button', true).first().dom.innerHTML = period;
16240 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16242 var cls = ['bottom'];
16244 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16251 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16256 this.picker().addClass(cls.join('-'));
16260 Roo.each(cls, function(c){
16262 _this.picker().setTop(_this.inputEl().getHeight());
16266 _this.picker().setTop(0 - _this.picker().getHeight());
16271 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16275 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16282 onFocus : function()
16284 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16288 onBlur : function()
16290 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16296 this.picker().show();
16301 this.fireEvent('show', this, this.date);
16306 this.picker().hide();
16309 this.fireEvent('hide', this, this.date);
16312 setTime : function()
16315 this.setValue(this.time.format(this.format));
16317 this.fireEvent('select', this, this.date);
16322 onMousedown: function(e){
16323 e.stopPropagation();
16324 e.preventDefault();
16327 onIncrementHours: function()
16329 Roo.log('onIncrementHours');
16330 this.time = this.time.add(Date.HOUR, 1);
16335 onDecrementHours: function()
16337 Roo.log('onDecrementHours');
16338 this.time = this.time.add(Date.HOUR, -1);
16342 onIncrementMinutes: function()
16344 Roo.log('onIncrementMinutes');
16345 this.time = this.time.add(Date.MINUTE, 1);
16349 onDecrementMinutes: function()
16351 Roo.log('onDecrementMinutes');
16352 this.time = this.time.add(Date.MINUTE, -1);
16356 onTogglePeriod: function()
16358 Roo.log('onTogglePeriod');
16359 this.time = this.time.add(Date.HOUR, 12);
16366 Roo.apply(Roo.bootstrap.TimeField, {
16396 cls: 'btn btn-info ok',
16408 Roo.apply(Roo.bootstrap.TimeField, {
16412 cls: 'datepicker dropdown-menu',
16416 cls: 'datepicker-time',
16420 cls: 'table-condensed',
16422 Roo.bootstrap.TimeField.content,
16423 Roo.bootstrap.TimeField.footer
16442 * @class Roo.bootstrap.MonthField
16443 * @extends Roo.bootstrap.Input
16444 * Bootstrap MonthField class
16446 * @cfg {String} language default en
16449 * Create a new MonthField
16450 * @param {Object} config The config object
16453 Roo.bootstrap.MonthField = function(config){
16454 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16459 * Fires when this field show.
16460 * @param {Roo.bootstrap.MonthField} this
16461 * @param {Mixed} date The date value
16466 * Fires when this field hide.
16467 * @param {Roo.bootstrap.MonthField} this
16468 * @param {Mixed} date The date value
16473 * Fires when select a date.
16474 * @param {Roo.bootstrap.MonthField} this
16475 * @param {String} oldvalue The old value
16476 * @param {String} newvalue The new value
16482 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16484 onRender: function(ct, position)
16487 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16489 this.language = this.language || 'en';
16490 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16491 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16493 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16494 this.isInline = false;
16495 this.isInput = true;
16496 this.component = this.el.select('.add-on', true).first() || false;
16497 this.component = (this.component && this.component.length === 0) ? false : this.component;
16498 this.hasInput = this.component && this.inputEL().length;
16500 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16502 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16504 this.picker().on('mousedown', this.onMousedown, this);
16505 this.picker().on('click', this.onClick, this);
16507 this.picker().addClass('datepicker-dropdown');
16509 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16510 v.setStyle('width', '189px');
16517 if(this.isInline) {
16523 setValue: function(v, suppressEvent)
16525 var o = this.getValue();
16527 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16531 if(suppressEvent !== true){
16532 this.fireEvent('select', this, o, v);
16537 getValue: function()
16542 onClick: function(e)
16544 e.stopPropagation();
16545 e.preventDefault();
16547 var target = e.getTarget();
16549 if(target.nodeName.toLowerCase() === 'i'){
16550 target = Roo.get(target).dom.parentNode;
16553 var nodeName = target.nodeName;
16554 var className = target.className;
16555 var html = target.innerHTML;
16557 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16561 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16563 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16569 picker : function()
16571 return this.pickerEl;
16574 fillMonths: function()
16577 var months = this.picker().select('>.datepicker-months td', true).first();
16579 months.dom.innerHTML = '';
16585 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16588 months.createChild(month);
16597 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16598 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16601 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16602 e.removeClass('active');
16604 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16605 e.addClass('active');
16612 if(this.isInline) return;
16614 this.picker().removeClass(['bottom', 'top']);
16616 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16618 * place to the top of element!
16622 this.picker().addClass('top');
16623 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16628 this.picker().addClass('bottom');
16630 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16633 onFocus : function()
16635 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16639 onBlur : function()
16641 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16643 var d = this.inputEl().getValue();
16652 this.picker().show();
16653 this.picker().select('>.datepicker-months', true).first().show();
16657 this.fireEvent('show', this, this.date);
16662 if(this.isInline) return;
16663 this.picker().hide();
16664 this.fireEvent('hide', this, this.date);
16668 onMousedown: function(e)
16670 e.stopPropagation();
16671 e.preventDefault();
16676 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16680 fireKey: function(e)
16682 if (!this.picker().isVisible()){
16683 if (e.keyCode == 27) // allow escape to hide and re-show picker
16693 e.preventDefault();
16697 dir = e.keyCode == 37 ? -1 : 1;
16699 this.vIndex = this.vIndex + dir;
16701 if(this.vIndex < 0){
16705 if(this.vIndex > 11){
16709 if(isNaN(this.vIndex)){
16713 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16719 dir = e.keyCode == 38 ? -1 : 1;
16721 this.vIndex = this.vIndex + dir * 4;
16723 if(this.vIndex < 0){
16727 if(this.vIndex > 11){
16731 if(isNaN(this.vIndex)){
16735 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16740 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16741 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16745 e.preventDefault();
16748 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16749 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16765 this.picker().remove();
16770 Roo.apply(Roo.bootstrap.MonthField, {
16789 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16790 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16795 Roo.apply(Roo.bootstrap.MonthField, {
16799 cls: 'datepicker dropdown-menu roo-dynamic',
16803 cls: 'datepicker-months',
16807 cls: 'table-condensed',
16809 Roo.bootstrap.DateField.content
16829 * @class Roo.bootstrap.CheckBox
16830 * @extends Roo.bootstrap.Input
16831 * Bootstrap CheckBox class
16833 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16834 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16835 * @cfg {String} boxLabel The text that appears beside the checkbox
16836 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16837 * @cfg {Boolean} checked initnal the element
16838 * @cfg {Boolean} inline inline the element (default false)
16839 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16842 * Create a new CheckBox
16843 * @param {Object} config The config object
16846 Roo.bootstrap.CheckBox = function(config){
16847 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16852 * Fires when the element is checked or unchecked.
16853 * @param {Roo.bootstrap.CheckBox} this This input
16854 * @param {Boolean} checked The new checked value
16861 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16863 inputType: 'checkbox',
16871 getAutoCreate : function()
16873 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16879 cfg.cls = 'form-group ' + this.inputType; //input-group
16882 cfg.cls += ' ' + this.inputType + '-inline';
16888 type : this.inputType,
16889 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16890 cls : 'roo-' + this.inputType, //'form-box',
16891 placeholder : this.placeholder || ''
16895 if (this.weight) { // Validity check?
16896 cfg.cls += " " + this.inputType + "-" + this.weight;
16899 if (this.disabled) {
16900 input.disabled=true;
16904 input.checked = this.checked;
16908 input.name = this.name;
16912 input.cls += ' input-' + this.size;
16917 ['xs','sm','md','lg'].map(function(size){
16918 if (settings[size]) {
16919 cfg.cls += ' col-' + size + '-' + settings[size];
16923 var inputblock = input;
16925 if (this.before || this.after) {
16928 cls : 'input-group',
16933 inputblock.cn.push({
16935 cls : 'input-group-addon',
16940 inputblock.cn.push(input);
16943 inputblock.cn.push({
16945 cls : 'input-group-addon',
16952 if (align ==='left' && this.fieldLabel.length) {
16953 Roo.log("left and has label");
16959 cls : 'control-label col-md-' + this.labelWidth,
16960 html : this.fieldLabel
16964 cls : "col-md-" + (12 - this.labelWidth),
16971 } else if ( this.fieldLabel.length) {
16976 tag: this.boxLabel ? 'span' : 'label',
16978 cls: 'control-label box-input-label',
16979 //cls : 'input-group-addon',
16980 html : this.fieldLabel
16990 Roo.log(" no label && no align");
16991 cfg.cn = [ inputblock ] ;
16996 var boxLabelCfg = {
16998 //'for': id, // box label is handled by onclick - so no for...
17000 html: this.boxLabel
17004 boxLabelCfg.tooltip = this.tooltip;
17007 cfg.cn.push(boxLabelCfg);
17017 * return the real input element.
17019 inputEl: function ()
17021 return this.el.select('input.roo-' + this.inputType,true).first();
17024 labelEl: function()
17026 return this.el.select('label.control-label',true).first();
17028 /* depricated... */
17032 return this.labelEl();
17035 initEvents : function()
17037 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17039 this.inputEl().on('click', this.onClick, this);
17041 if (this.boxLabel) {
17042 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17045 this.startValue = this.getValue();
17048 Roo.bootstrap.CheckBox.register(this);
17052 onClick : function()
17054 this.setChecked(!this.checked);
17057 setChecked : function(state,suppressEvent)
17059 this.startValue = this.getValue();
17061 if(this.inputType == 'radio'){
17063 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17064 e.dom.checked = false;
17067 this.inputEl().dom.checked = true;
17069 this.inputEl().dom.value = this.inputValue;
17071 if(suppressEvent !== true){
17072 this.fireEvent('check', this, true);
17080 this.checked = state;
17082 this.inputEl().dom.checked = state;
17084 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17086 if(suppressEvent !== true){
17087 this.fireEvent('check', this, state);
17093 getValue : function()
17095 if(this.inputType == 'radio'){
17096 return this.getGroupValue();
17099 return this.inputEl().getValue();
17103 getGroupValue : function()
17105 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17109 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17112 setValue : function(v,suppressEvent)
17114 if(this.inputType == 'radio'){
17115 this.setGroupValue(v, suppressEvent);
17119 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17124 setGroupValue : function(v, suppressEvent)
17126 this.startValue = this.getValue();
17128 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17129 e.dom.checked = false;
17131 if(e.dom.value == v){
17132 e.dom.checked = true;
17136 if(suppressEvent !== true){
17137 this.fireEvent('check', this, true);
17145 validate : function()
17149 (this.inputType == 'radio' && this.validateRadio()) ||
17150 (this.inputType == 'checkbox' && this.validateCheckbox())
17156 this.markInvalid();
17160 validateRadio : function()
17164 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17165 if(!e.dom.checked){
17177 validateCheckbox : function()
17180 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17183 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17191 for(var i in group){
17196 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17203 * Mark this field as valid
17205 markValid : function()
17207 if(this.allowBlank){
17213 this.fireEvent('valid', this);
17215 if(this.inputType == 'radio'){
17216 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17217 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17218 e.findParent('.form-group', false, true).addClass(_this.validClass);
17225 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17226 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17230 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17236 for(var i in group){
17237 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17238 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17243 * Mark this field as invalid
17244 * @param {String} msg The validation message
17246 markInvalid : function(msg)
17248 if(this.allowBlank){
17254 this.fireEvent('invalid', this, msg);
17256 if(this.inputType == 'radio'){
17257 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17258 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17259 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17266 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17267 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17271 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17277 for(var i in group){
17278 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17279 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17286 Roo.apply(Roo.bootstrap.CheckBox, {
17291 * register a CheckBox Group
17292 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17294 register : function(checkbox)
17296 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17297 this.groups[checkbox.groupId] = {};
17300 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17304 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17308 * fetch a CheckBox Group based on the group ID
17309 * @param {string} the group ID
17310 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17312 get: function(groupId) {
17313 if (typeof(this.groups[groupId]) == 'undefined') {
17317 return this.groups[groupId] ;
17329 *<div class="radio">
17331 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17332 Option one is this and that—be sure to include why it's great
17339 *<label class="radio-inline">fieldLabel</label>
17340 *<label class="radio-inline">
17341 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17349 * @class Roo.bootstrap.Radio
17350 * @extends Roo.bootstrap.CheckBox
17351 * Bootstrap Radio class
17354 * Create a new Radio
17355 * @param {Object} config The config object
17358 Roo.bootstrap.Radio = function(config){
17359 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17363 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17365 inputType: 'radio',
17369 getAutoCreate : function()
17371 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17372 align = align || 'left'; // default...
17379 tag : this.inline ? 'span' : 'div',
17384 var inline = this.inline ? ' radio-inline' : '';
17388 // does not need for, as we wrap the input with it..
17390 cls : 'control-label box-label' + inline,
17393 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17397 //cls : 'control-label' + inline,
17398 html : this.fieldLabel,
17399 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17408 type : this.inputType,
17409 //value : (!this.checked) ? this.valueOff : this.inputValue,
17410 value : this.inputValue,
17412 placeholder : this.placeholder || '' // ?? needed????
17415 if (this.weight) { // Validity check?
17416 input.cls += " radio-" + this.weight;
17418 if (this.disabled) {
17419 input.disabled=true;
17423 input.checked = this.checked;
17427 input.name = this.name;
17431 input.cls += ' input-' + this.size;
17434 //?? can span's inline have a width??
17437 ['xs','sm','md','lg'].map(function(size){
17438 if (settings[size]) {
17439 cfg.cls += ' col-' + size + '-' + settings[size];
17443 var inputblock = input;
17445 if (this.before || this.after) {
17448 cls : 'input-group',
17453 inputblock.cn.push({
17455 cls : 'input-group-addon',
17459 inputblock.cn.push(input);
17461 inputblock.cn.push({
17463 cls : 'input-group-addon',
17471 if (this.fieldLabel && this.fieldLabel.length) {
17472 cfg.cn.push(fieldLabel);
17475 // normal bootstrap puts the input inside the label.
17476 // however with our styled version - it has to go after the input.
17478 //lbl.cn.push(inputblock);
17482 cls: 'radio' + inline,
17489 cfg.cn.push( lblwrap);
17494 html: this.boxLabel
17503 initEvents : function()
17505 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17507 this.inputEl().on('click', this.onClick, this);
17508 if (this.boxLabel) {
17509 Roo.log('find label')
17510 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17515 inputEl: function ()
17517 return this.el.select('input.roo-radio',true).first();
17519 onClick : function()
17522 this.setChecked(true);
17525 setChecked : function(state,suppressEvent)
17528 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17529 v.dom.checked = false;
17532 Roo.log(this.inputEl().dom);
17533 this.checked = state;
17534 this.inputEl().dom.checked = state;
17536 if(suppressEvent !== true){
17537 this.fireEvent('check', this, state);
17540 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17544 getGroupValue : function()
17547 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17548 if(v.dom.checked == true){
17549 value = v.dom.value;
17557 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17558 * @return {Mixed} value The field value
17560 getValue : function(){
17561 return this.getGroupValue();
17567 //<script type="text/javascript">
17570 * Based Ext JS Library 1.1.1
17571 * Copyright(c) 2006-2007, Ext JS, LLC.
17577 * @class Roo.HtmlEditorCore
17578 * @extends Roo.Component
17579 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17581 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17584 Roo.HtmlEditorCore = function(config){
17587 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17592 * @event initialize
17593 * Fires when the editor is fully initialized (including the iframe)
17594 * @param {Roo.HtmlEditorCore} this
17599 * Fires when the editor is first receives the focus. Any insertion must wait
17600 * until after this event.
17601 * @param {Roo.HtmlEditorCore} this
17605 * @event beforesync
17606 * Fires before the textarea is updated with content from the editor iframe. Return false
17607 * to cancel the sync.
17608 * @param {Roo.HtmlEditorCore} this
17609 * @param {String} html
17613 * @event beforepush
17614 * Fires before the iframe editor is updated with content from the textarea. Return false
17615 * to cancel the push.
17616 * @param {Roo.HtmlEditorCore} this
17617 * @param {String} html
17622 * Fires when the textarea is updated with content from the editor iframe.
17623 * @param {Roo.HtmlEditorCore} this
17624 * @param {String} html
17629 * Fires when the iframe editor is updated with content from the textarea.
17630 * @param {Roo.HtmlEditorCore} this
17631 * @param {String} html
17636 * @event editorevent
17637 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17638 * @param {Roo.HtmlEditorCore} this
17644 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17646 // defaults : white / black...
17647 this.applyBlacklists();
17654 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17658 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17664 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17669 * @cfg {Number} height (in pixels)
17673 * @cfg {Number} width (in pixels)
17678 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17681 stylesheets: false,
17686 // private properties
17687 validationEvent : false,
17689 initialized : false,
17691 sourceEditMode : false,
17692 onFocus : Roo.emptyFn,
17694 hideMode:'offsets',
17698 // blacklist + whitelisted elements..
17705 * Protected method that will not generally be called directly. It
17706 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17707 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17709 getDocMarkup : function(){
17713 // inherit styels from page...??
17714 if (this.stylesheets === false) {
17716 Roo.get(document.head).select('style').each(function(node) {
17717 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17720 Roo.get(document.head).select('link').each(function(node) {
17721 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17724 } else if (!this.stylesheets.length) {
17726 st = '<style type="text/css">' +
17727 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17733 st += '<style type="text/css">' +
17734 'IMG { cursor: pointer } ' +
17738 return '<html><head>' + st +
17739 //<style type="text/css">' +
17740 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17742 ' </head><body class="roo-htmleditor-body"></body></html>';
17746 onRender : function(ct, position)
17749 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17750 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17753 this.el.dom.style.border = '0 none';
17754 this.el.dom.setAttribute('tabIndex', -1);
17755 this.el.addClass('x-hidden hide');
17759 if(Roo.isIE){ // fix IE 1px bogus margin
17760 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17764 this.frameId = Roo.id();
17768 var iframe = this.owner.wrap.createChild({
17770 cls: 'form-control', // bootstrap..
17772 name: this.frameId,
17773 frameBorder : 'no',
17774 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17779 this.iframe = iframe.dom;
17781 this.assignDocWin();
17783 this.doc.designMode = 'on';
17786 this.doc.write(this.getDocMarkup());
17790 var task = { // must defer to wait for browser to be ready
17792 //console.log("run task?" + this.doc.readyState);
17793 this.assignDocWin();
17794 if(this.doc.body || this.doc.readyState == 'complete'){
17796 this.doc.designMode="on";
17800 Roo.TaskMgr.stop(task);
17801 this.initEditor.defer(10, this);
17808 Roo.TaskMgr.start(task);
17813 onResize : function(w, h)
17815 Roo.log('resize: ' +w + ',' + h );
17816 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17820 if(typeof w == 'number'){
17822 this.iframe.style.width = w + 'px';
17824 if(typeof h == 'number'){
17826 this.iframe.style.height = h + 'px';
17828 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17835 * Toggles the editor between standard and source edit mode.
17836 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17838 toggleSourceEdit : function(sourceEditMode){
17840 this.sourceEditMode = sourceEditMode === true;
17842 if(this.sourceEditMode){
17844 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17847 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17848 //this.iframe.className = '';
17851 //this.setSize(this.owner.wrap.getSize());
17852 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17859 * Protected method that will not generally be called directly. If you need/want
17860 * custom HTML cleanup, this is the method you should override.
17861 * @param {String} html The HTML to be cleaned
17862 * return {String} The cleaned HTML
17864 cleanHtml : function(html){
17865 html = String(html);
17866 if(html.length > 5){
17867 if(Roo.isSafari){ // strip safari nonsense
17868 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17871 if(html == ' '){
17878 * HTML Editor -> Textarea
17879 * Protected method that will not generally be called directly. Syncs the contents
17880 * of the editor iframe with the textarea.
17882 syncValue : function(){
17883 if(this.initialized){
17884 var bd = (this.doc.body || this.doc.documentElement);
17885 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17886 var html = bd.innerHTML;
17888 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17889 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17891 html = '<div style="'+m[0]+'">' + html + '</div>';
17894 html = this.cleanHtml(html);
17895 // fix up the special chars.. normaly like back quotes in word...
17896 // however we do not want to do this with chinese..
17897 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17898 var cc = b.charCodeAt();
17900 (cc >= 0x4E00 && cc < 0xA000 ) ||
17901 (cc >= 0x3400 && cc < 0x4E00 ) ||
17902 (cc >= 0xf900 && cc < 0xfb00 )
17908 if(this.owner.fireEvent('beforesync', this, html) !== false){
17909 this.el.dom.value = html;
17910 this.owner.fireEvent('sync', this, html);
17916 * Protected method that will not generally be called directly. Pushes the value of the textarea
17917 * into the iframe editor.
17919 pushValue : function(){
17920 if(this.initialized){
17921 var v = this.el.dom.value.trim();
17923 // if(v.length < 1){
17927 if(this.owner.fireEvent('beforepush', this, v) !== false){
17928 var d = (this.doc.body || this.doc.documentElement);
17930 this.cleanUpPaste();
17931 this.el.dom.value = d.innerHTML;
17932 this.owner.fireEvent('push', this, v);
17938 deferFocus : function(){
17939 this.focus.defer(10, this);
17943 focus : function(){
17944 if(this.win && !this.sourceEditMode){
17951 assignDocWin: function()
17953 var iframe = this.iframe;
17956 this.doc = iframe.contentWindow.document;
17957 this.win = iframe.contentWindow;
17959 // if (!Roo.get(this.frameId)) {
17962 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17963 // this.win = Roo.get(this.frameId).dom.contentWindow;
17965 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17969 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17970 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17975 initEditor : function(){
17976 //console.log("INIT EDITOR");
17977 this.assignDocWin();
17981 this.doc.designMode="on";
17983 this.doc.write(this.getDocMarkup());
17986 var dbody = (this.doc.body || this.doc.documentElement);
17987 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17988 // this copies styles from the containing element into thsi one..
17989 // not sure why we need all of this..
17990 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17992 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17993 //ss['background-attachment'] = 'fixed'; // w3c
17994 dbody.bgProperties = 'fixed'; // ie
17995 //Roo.DomHelper.applyStyles(dbody, ss);
17996 Roo.EventManager.on(this.doc, {
17997 //'mousedown': this.onEditorEvent,
17998 'mouseup': this.onEditorEvent,
17999 'dblclick': this.onEditorEvent,
18000 'click': this.onEditorEvent,
18001 'keyup': this.onEditorEvent,
18006 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18008 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18009 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18011 this.initialized = true;
18013 this.owner.fireEvent('initialize', this);
18018 onDestroy : function(){
18024 //for (var i =0; i < this.toolbars.length;i++) {
18025 // // fixme - ask toolbars for heights?
18026 // this.toolbars[i].onDestroy();
18029 //this.wrap.dom.innerHTML = '';
18030 //this.wrap.remove();
18035 onFirstFocus : function(){
18037 this.assignDocWin();
18040 this.activated = true;
18043 if(Roo.isGecko){ // prevent silly gecko errors
18045 var s = this.win.getSelection();
18046 if(!s.focusNode || s.focusNode.nodeType != 3){
18047 var r = s.getRangeAt(0);
18048 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18053 this.execCmd('useCSS', true);
18054 this.execCmd('styleWithCSS', false);
18057 this.owner.fireEvent('activate', this);
18061 adjustFont: function(btn){
18062 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18063 //if(Roo.isSafari){ // safari
18066 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18067 if(Roo.isSafari){ // safari
18068 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18069 v = (v < 10) ? 10 : v;
18070 v = (v > 48) ? 48 : v;
18071 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18076 v = Math.max(1, v+adjust);
18078 this.execCmd('FontSize', v );
18081 onEditorEvent : function(e){
18082 this.owner.fireEvent('editorevent', this, e);
18083 // this.updateToolbar();
18084 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18087 insertTag : function(tg)
18089 // could be a bit smarter... -> wrap the current selected tRoo..
18090 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18092 range = this.createRange(this.getSelection());
18093 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18094 wrappingNode.appendChild(range.extractContents());
18095 range.insertNode(wrappingNode);
18102 this.execCmd("formatblock", tg);
18106 insertText : function(txt)
18110 var range = this.createRange();
18111 range.deleteContents();
18112 //alert(Sender.getAttribute('label'));
18114 range.insertNode(this.doc.createTextNode(txt));
18120 * Executes a Midas editor command on the editor document and performs necessary focus and
18121 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18122 * @param {String} cmd The Midas command
18123 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18125 relayCmd : function(cmd, value){
18127 this.execCmd(cmd, value);
18128 this.owner.fireEvent('editorevent', this);
18129 //this.updateToolbar();
18130 this.owner.deferFocus();
18134 * Executes a Midas editor command directly on the editor document.
18135 * For visual commands, you should use {@link #relayCmd} instead.
18136 * <b>This should only be called after the editor is initialized.</b>
18137 * @param {String} cmd The Midas command
18138 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18140 execCmd : function(cmd, value){
18141 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18148 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18150 * @param {String} text | dom node..
18152 insertAtCursor : function(text)
18157 if(!this.activated){
18163 var r = this.doc.selection.createRange();
18174 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18178 // from jquery ui (MIT licenced)
18180 var win = this.win;
18182 if (win.getSelection && win.getSelection().getRangeAt) {
18183 range = win.getSelection().getRangeAt(0);
18184 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18185 range.insertNode(node);
18186 } else if (win.document.selection && win.document.selection.createRange) {
18187 // no firefox support
18188 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18189 win.document.selection.createRange().pasteHTML(txt);
18191 // no firefox support
18192 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18193 this.execCmd('InsertHTML', txt);
18202 mozKeyPress : function(e){
18204 var c = e.getCharCode(), cmd;
18207 c = String.fromCharCode(c).toLowerCase();
18221 this.cleanUpPaste.defer(100, this);
18229 e.preventDefault();
18237 fixKeys : function(){ // load time branching for fastest keydown performance
18239 return function(e){
18240 var k = e.getKey(), r;
18243 r = this.doc.selection.createRange();
18246 r.pasteHTML('    ');
18253 r = this.doc.selection.createRange();
18255 var target = r.parentElement();
18256 if(!target || target.tagName.toLowerCase() != 'li'){
18258 r.pasteHTML('<br />');
18264 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18265 this.cleanUpPaste.defer(100, this);
18271 }else if(Roo.isOpera){
18272 return function(e){
18273 var k = e.getKey();
18277 this.execCmd('InsertHTML','    ');
18280 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18281 this.cleanUpPaste.defer(100, this);
18286 }else if(Roo.isSafari){
18287 return function(e){
18288 var k = e.getKey();
18292 this.execCmd('InsertText','\t');
18296 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18297 this.cleanUpPaste.defer(100, this);
18305 getAllAncestors: function()
18307 var p = this.getSelectedNode();
18310 a.push(p); // push blank onto stack..
18311 p = this.getParentElement();
18315 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18319 a.push(this.doc.body);
18323 lastSelNode : false,
18326 getSelection : function()
18328 this.assignDocWin();
18329 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18332 getSelectedNode: function()
18334 // this may only work on Gecko!!!
18336 // should we cache this!!!!
18341 var range = this.createRange(this.getSelection()).cloneRange();
18344 var parent = range.parentElement();
18346 var testRange = range.duplicate();
18347 testRange.moveToElementText(parent);
18348 if (testRange.inRange(range)) {
18351 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18354 parent = parent.parentElement;
18359 // is ancestor a text element.
18360 var ac = range.commonAncestorContainer;
18361 if (ac.nodeType == 3) {
18362 ac = ac.parentNode;
18365 var ar = ac.childNodes;
18368 var other_nodes = [];
18369 var has_other_nodes = false;
18370 for (var i=0;i<ar.length;i++) {
18371 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18374 // fullly contained node.
18376 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18381 // probably selected..
18382 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18383 other_nodes.push(ar[i]);
18387 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18392 has_other_nodes = true;
18394 if (!nodes.length && other_nodes.length) {
18395 nodes= other_nodes;
18397 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18403 createRange: function(sel)
18405 // this has strange effects when using with
18406 // top toolbar - not sure if it's a great idea.
18407 //this.editor.contentWindow.focus();
18408 if (typeof sel != "undefined") {
18410 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18412 return this.doc.createRange();
18415 return this.doc.createRange();
18418 getParentElement: function()
18421 this.assignDocWin();
18422 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18424 var range = this.createRange(sel);
18427 var p = range.commonAncestorContainer;
18428 while (p.nodeType == 3) { // text node
18439 * Range intersection.. the hard stuff...
18443 * [ -- selected range --- ]
18447 * if end is before start or hits it. fail.
18448 * if start is after end or hits it fail.
18450 * if either hits (but other is outside. - then it's not
18456 // @see http://www.thismuchiknow.co.uk/?p=64.
18457 rangeIntersectsNode : function(range, node)
18459 var nodeRange = node.ownerDocument.createRange();
18461 nodeRange.selectNode(node);
18463 nodeRange.selectNodeContents(node);
18466 var rangeStartRange = range.cloneRange();
18467 rangeStartRange.collapse(true);
18469 var rangeEndRange = range.cloneRange();
18470 rangeEndRange.collapse(false);
18472 var nodeStartRange = nodeRange.cloneRange();
18473 nodeStartRange.collapse(true);
18475 var nodeEndRange = nodeRange.cloneRange();
18476 nodeEndRange.collapse(false);
18478 return rangeStartRange.compareBoundaryPoints(
18479 Range.START_TO_START, nodeEndRange) == -1 &&
18480 rangeEndRange.compareBoundaryPoints(
18481 Range.START_TO_START, nodeStartRange) == 1;
18485 rangeCompareNode : function(range, node)
18487 var nodeRange = node.ownerDocument.createRange();
18489 nodeRange.selectNode(node);
18491 nodeRange.selectNodeContents(node);
18495 range.collapse(true);
18497 nodeRange.collapse(true);
18499 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18500 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18502 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18504 var nodeIsBefore = ss == 1;
18505 var nodeIsAfter = ee == -1;
18507 if (nodeIsBefore && nodeIsAfter)
18509 if (!nodeIsBefore && nodeIsAfter)
18510 return 1; //right trailed.
18512 if (nodeIsBefore && !nodeIsAfter)
18513 return 2; // left trailed.
18518 // private? - in a new class?
18519 cleanUpPaste : function()
18521 // cleans up the whole document..
18522 Roo.log('cleanuppaste');
18524 this.cleanUpChildren(this.doc.body);
18525 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18526 if (clean != this.doc.body.innerHTML) {
18527 this.doc.body.innerHTML = clean;
18532 cleanWordChars : function(input) {// change the chars to hex code
18533 var he = Roo.HtmlEditorCore;
18535 var output = input;
18536 Roo.each(he.swapCodes, function(sw) {
18537 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18539 output = output.replace(swapper, sw[1]);
18546 cleanUpChildren : function (n)
18548 if (!n.childNodes.length) {
18551 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18552 this.cleanUpChild(n.childNodes[i]);
18559 cleanUpChild : function (node)
18562 //console.log(node);
18563 if (node.nodeName == "#text") {
18564 // clean up silly Windows -- stuff?
18567 if (node.nodeName == "#comment") {
18568 node.parentNode.removeChild(node);
18569 // clean up silly Windows -- stuff?
18572 var lcname = node.tagName.toLowerCase();
18573 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18574 // whitelist of tags..
18576 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18578 node.parentNode.removeChild(node);
18583 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18585 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18586 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18588 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18589 // remove_keep_children = true;
18592 if (remove_keep_children) {
18593 this.cleanUpChildren(node);
18594 // inserts everything just before this node...
18595 while (node.childNodes.length) {
18596 var cn = node.childNodes[0];
18597 node.removeChild(cn);
18598 node.parentNode.insertBefore(cn, node);
18600 node.parentNode.removeChild(node);
18604 if (!node.attributes || !node.attributes.length) {
18605 this.cleanUpChildren(node);
18609 function cleanAttr(n,v)
18612 if (v.match(/^\./) || v.match(/^\//)) {
18615 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18618 if (v.match(/^#/)) {
18621 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18622 node.removeAttribute(n);
18626 var cwhite = this.cwhite;
18627 var cblack = this.cblack;
18629 function cleanStyle(n,v)
18631 if (v.match(/expression/)) { //XSS?? should we even bother..
18632 node.removeAttribute(n);
18636 var parts = v.split(/;/);
18639 Roo.each(parts, function(p) {
18640 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18644 var l = p.split(':').shift().replace(/\s+/g,'');
18645 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18647 if ( cwhite.length && cblack.indexOf(l) > -1) {
18648 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18649 //node.removeAttribute(n);
18653 // only allow 'c whitelisted system attributes'
18654 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18655 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18656 //node.removeAttribute(n);
18666 if (clean.length) {
18667 node.setAttribute(n, clean.join(';'));
18669 node.removeAttribute(n);
18675 for (var i = node.attributes.length-1; i > -1 ; i--) {
18676 var a = node.attributes[i];
18679 if (a.name.toLowerCase().substr(0,2)=='on') {
18680 node.removeAttribute(a.name);
18683 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18684 node.removeAttribute(a.name);
18687 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18688 cleanAttr(a.name,a.value); // fixme..
18691 if (a.name == 'style') {
18692 cleanStyle(a.name,a.value);
18695 /// clean up MS crap..
18696 // tecnically this should be a list of valid class'es..
18699 if (a.name == 'class') {
18700 if (a.value.match(/^Mso/)) {
18701 node.className = '';
18704 if (a.value.match(/body/)) {
18705 node.className = '';
18716 this.cleanUpChildren(node);
18721 * Clean up MS wordisms...
18723 cleanWord : function(node)
18726 var cleanWordChildren = function()
18728 if (!node.childNodes.length) {
18731 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18732 _t.cleanWord(node.childNodes[i]);
18738 this.cleanWord(this.doc.body);
18741 if (node.nodeName == "#text") {
18742 // clean up silly Windows -- stuff?
18745 if (node.nodeName == "#comment") {
18746 node.parentNode.removeChild(node);
18747 // clean up silly Windows -- stuff?
18751 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18752 node.parentNode.removeChild(node);
18756 // remove - but keep children..
18757 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18758 while (node.childNodes.length) {
18759 var cn = node.childNodes[0];
18760 node.removeChild(cn);
18761 node.parentNode.insertBefore(cn, node);
18763 node.parentNode.removeChild(node);
18764 cleanWordChildren();
18768 if (node.className.length) {
18770 var cn = node.className.split(/\W+/);
18772 Roo.each(cn, function(cls) {
18773 if (cls.match(/Mso[a-zA-Z]+/)) {
18778 node.className = cna.length ? cna.join(' ') : '';
18780 node.removeAttribute("class");
18784 if (node.hasAttribute("lang")) {
18785 node.removeAttribute("lang");
18788 if (node.hasAttribute("style")) {
18790 var styles = node.getAttribute("style").split(";");
18792 Roo.each(styles, function(s) {
18793 if (!s.match(/:/)) {
18796 var kv = s.split(":");
18797 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18800 // what ever is left... we allow.
18803 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18804 if (!nstyle.length) {
18805 node.removeAttribute('style');
18809 cleanWordChildren();
18813 domToHTML : function(currentElement, depth, nopadtext) {
18815 depth = depth || 0;
18816 nopadtext = nopadtext || false;
18818 if (!currentElement) {
18819 return this.domToHTML(this.doc.body);
18822 //Roo.log(currentElement);
18824 var allText = false;
18825 var nodeName = currentElement.nodeName;
18826 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18828 if (nodeName == '#text') {
18830 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18835 if (nodeName != 'BODY') {
18838 // Prints the node tagName, such as <A>, <IMG>, etc
18841 for(i = 0; i < currentElement.attributes.length;i++) {
18843 var aname = currentElement.attributes.item(i).name;
18844 if (!currentElement.attributes.item(i).value.length) {
18847 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18850 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18859 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18862 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18867 // Traverse the tree
18869 var currentElementChild = currentElement.childNodes.item(i);
18870 var allText = true;
18871 var innerHTML = '';
18873 while (currentElementChild) {
18874 // Formatting code (indent the tree so it looks nice on the screen)
18875 var nopad = nopadtext;
18876 if (lastnode == 'SPAN') {
18880 if (currentElementChild.nodeName == '#text') {
18881 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18882 toadd = nopadtext ? toadd : toadd.trim();
18883 if (!nopad && toadd.length > 80) {
18884 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18886 innerHTML += toadd;
18889 currentElementChild = currentElement.childNodes.item(i);
18895 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18897 // Recursively traverse the tree structure of the child node
18898 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18899 lastnode = currentElementChild.nodeName;
18901 currentElementChild=currentElement.childNodes.item(i);
18907 // The remaining code is mostly for formatting the tree
18908 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18913 ret+= "</"+tagName+">";
18919 applyBlacklists : function()
18921 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18922 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18926 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18927 if (b.indexOf(tag) > -1) {
18930 this.white.push(tag);
18934 Roo.each(w, function(tag) {
18935 if (b.indexOf(tag) > -1) {
18938 if (this.white.indexOf(tag) > -1) {
18941 this.white.push(tag);
18946 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18947 if (w.indexOf(tag) > -1) {
18950 this.black.push(tag);
18954 Roo.each(b, function(tag) {
18955 if (w.indexOf(tag) > -1) {
18958 if (this.black.indexOf(tag) > -1) {
18961 this.black.push(tag);
18966 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18967 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18971 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18972 if (b.indexOf(tag) > -1) {
18975 this.cwhite.push(tag);
18979 Roo.each(w, function(tag) {
18980 if (b.indexOf(tag) > -1) {
18983 if (this.cwhite.indexOf(tag) > -1) {
18986 this.cwhite.push(tag);
18991 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18992 if (w.indexOf(tag) > -1) {
18995 this.cblack.push(tag);
18999 Roo.each(b, function(tag) {
19000 if (w.indexOf(tag) > -1) {
19003 if (this.cblack.indexOf(tag) > -1) {
19006 this.cblack.push(tag);
19011 setStylesheets : function(stylesheets)
19013 if(typeof(stylesheets) == 'string'){
19014 Roo.get(this.iframe.contentDocument.head).createChild({
19016 rel : 'stylesheet',
19025 Roo.each(stylesheets, function(s) {
19030 Roo.get(_this.iframe.contentDocument.head).createChild({
19032 rel : 'stylesheet',
19041 removeStylesheets : function()
19045 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19050 // hide stuff that is not compatible
19064 * @event specialkey
19068 * @cfg {String} fieldClass @hide
19071 * @cfg {String} focusClass @hide
19074 * @cfg {String} autoCreate @hide
19077 * @cfg {String} inputType @hide
19080 * @cfg {String} invalidClass @hide
19083 * @cfg {String} invalidText @hide
19086 * @cfg {String} msgFx @hide
19089 * @cfg {String} validateOnBlur @hide
19093 Roo.HtmlEditorCore.white = [
19094 'area', 'br', 'img', 'input', 'hr', 'wbr',
19096 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19097 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19098 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19099 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19100 'table', 'ul', 'xmp',
19102 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19105 'dir', 'menu', 'ol', 'ul', 'dl',
19111 Roo.HtmlEditorCore.black = [
19112 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19114 'base', 'basefont', 'bgsound', 'blink', 'body',
19115 'frame', 'frameset', 'head', 'html', 'ilayer',
19116 'iframe', 'layer', 'link', 'meta', 'object',
19117 'script', 'style' ,'title', 'xml' // clean later..
19119 Roo.HtmlEditorCore.clean = [
19120 'script', 'style', 'title', 'xml'
19122 Roo.HtmlEditorCore.remove = [
19127 Roo.HtmlEditorCore.ablack = [
19131 Roo.HtmlEditorCore.aclean = [
19132 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19136 Roo.HtmlEditorCore.pwhite= [
19137 'http', 'https', 'mailto'
19140 // white listed style attributes.
19141 Roo.HtmlEditorCore.cwhite= [
19142 // 'text-align', /// default is to allow most things..
19148 // black listed style attributes.
19149 Roo.HtmlEditorCore.cblack= [
19150 // 'font-size' -- this can be set by the project
19154 Roo.HtmlEditorCore.swapCodes =[
19173 * @class Roo.bootstrap.HtmlEditor
19174 * @extends Roo.bootstrap.TextArea
19175 * Bootstrap HtmlEditor class
19178 * Create a new HtmlEditor
19179 * @param {Object} config The config object
19182 Roo.bootstrap.HtmlEditor = function(config){
19183 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19184 if (!this.toolbars) {
19185 this.toolbars = [];
19187 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19190 * @event initialize
19191 * Fires when the editor is fully initialized (including the iframe)
19192 * @param {HtmlEditor} this
19197 * Fires when the editor is first receives the focus. Any insertion must wait
19198 * until after this event.
19199 * @param {HtmlEditor} this
19203 * @event beforesync
19204 * Fires before the textarea is updated with content from the editor iframe. Return false
19205 * to cancel the sync.
19206 * @param {HtmlEditor} this
19207 * @param {String} html
19211 * @event beforepush
19212 * Fires before the iframe editor is updated with content from the textarea. Return false
19213 * to cancel the push.
19214 * @param {HtmlEditor} this
19215 * @param {String} html
19220 * Fires when the textarea is updated with content from the editor iframe.
19221 * @param {HtmlEditor} this
19222 * @param {String} html
19227 * Fires when the iframe editor is updated with content from the textarea.
19228 * @param {HtmlEditor} this
19229 * @param {String} html
19233 * @event editmodechange
19234 * Fires when the editor switches edit modes
19235 * @param {HtmlEditor} this
19236 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19238 editmodechange: true,
19240 * @event editorevent
19241 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19242 * @param {HtmlEditor} this
19246 * @event firstfocus
19247 * Fires when on first focus - needed by toolbars..
19248 * @param {HtmlEditor} this
19253 * Auto save the htmlEditor value as a file into Events
19254 * @param {HtmlEditor} this
19258 * @event savedpreview
19259 * preview the saved version of htmlEditor
19260 * @param {HtmlEditor} this
19267 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19271 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19276 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19281 * @cfg {Number} height (in pixels)
19285 * @cfg {Number} width (in pixels)
19290 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19293 stylesheets: false,
19298 // private properties
19299 validationEvent : false,
19301 initialized : false,
19304 onFocus : Roo.emptyFn,
19306 hideMode:'offsets',
19309 tbContainer : false,
19311 toolbarContainer :function() {
19312 return this.wrap.select('.x-html-editor-tb',true).first();
19316 * Protected method that will not generally be called directly. It
19317 * is called when the editor creates its toolbar. Override this method if you need to
19318 * add custom toolbar buttons.
19319 * @param {HtmlEditor} editor
19321 createToolbar : function(){
19323 Roo.log("create toolbars");
19325 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19326 this.toolbars[0].render(this.toolbarContainer());
19330 // if (!editor.toolbars || !editor.toolbars.length) {
19331 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19334 // for (var i =0 ; i < editor.toolbars.length;i++) {
19335 // editor.toolbars[i] = Roo.factory(
19336 // typeof(editor.toolbars[i]) == 'string' ?
19337 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19338 // Roo.bootstrap.HtmlEditor);
19339 // editor.toolbars[i].init(editor);
19345 onRender : function(ct, position)
19347 // Roo.log("Call onRender: " + this.xtype);
19349 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19351 this.wrap = this.inputEl().wrap({
19352 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19355 this.editorcore.onRender(ct, position);
19357 if (this.resizable) {
19358 this.resizeEl = new Roo.Resizable(this.wrap, {
19362 minHeight : this.height,
19363 height: this.height,
19364 handles : this.resizable,
19367 resize : function(r, w, h) {
19368 _t.onResize(w,h); // -something
19374 this.createToolbar(this);
19377 if(!this.width && this.resizable){
19378 this.setSize(this.wrap.getSize());
19380 if (this.resizeEl) {
19381 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19382 // should trigger onReize..
19388 onResize : function(w, h)
19390 Roo.log('resize: ' +w + ',' + h );
19391 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19395 if(this.inputEl() ){
19396 if(typeof w == 'number'){
19397 var aw = w - this.wrap.getFrameWidth('lr');
19398 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19401 if(typeof h == 'number'){
19402 var tbh = -11; // fixme it needs to tool bar size!
19403 for (var i =0; i < this.toolbars.length;i++) {
19404 // fixme - ask toolbars for heights?
19405 tbh += this.toolbars[i].el.getHeight();
19406 //if (this.toolbars[i].footer) {
19407 // tbh += this.toolbars[i].footer.el.getHeight();
19415 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19416 ah -= 5; // knock a few pixes off for look..
19417 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19421 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19422 this.editorcore.onResize(ew,eh);
19427 * Toggles the editor between standard and source edit mode.
19428 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19430 toggleSourceEdit : function(sourceEditMode)
19432 this.editorcore.toggleSourceEdit(sourceEditMode);
19434 if(this.editorcore.sourceEditMode){
19435 Roo.log('editor - showing textarea');
19438 // Roo.log(this.syncValue());
19440 this.inputEl().removeClass(['hide', 'x-hidden']);
19441 this.inputEl().dom.removeAttribute('tabIndex');
19442 this.inputEl().focus();
19444 Roo.log('editor - hiding textarea');
19446 // Roo.log(this.pushValue());
19449 this.inputEl().addClass(['hide', 'x-hidden']);
19450 this.inputEl().dom.setAttribute('tabIndex', -1);
19451 //this.deferFocus();
19454 if(this.resizable){
19455 this.setSize(this.wrap.getSize());
19458 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19461 // private (for BoxComponent)
19462 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19464 // private (for BoxComponent)
19465 getResizeEl : function(){
19469 // private (for BoxComponent)
19470 getPositionEl : function(){
19475 initEvents : function(){
19476 this.originalValue = this.getValue();
19480 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19483 // markInvalid : Roo.emptyFn,
19485 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19488 // clearInvalid : Roo.emptyFn,
19490 setValue : function(v){
19491 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19492 this.editorcore.pushValue();
19497 deferFocus : function(){
19498 this.focus.defer(10, this);
19502 focus : function(){
19503 this.editorcore.focus();
19509 onDestroy : function(){
19515 for (var i =0; i < this.toolbars.length;i++) {
19516 // fixme - ask toolbars for heights?
19517 this.toolbars[i].onDestroy();
19520 this.wrap.dom.innerHTML = '';
19521 this.wrap.remove();
19526 onFirstFocus : function(){
19527 //Roo.log("onFirstFocus");
19528 this.editorcore.onFirstFocus();
19529 for (var i =0; i < this.toolbars.length;i++) {
19530 this.toolbars[i].onFirstFocus();
19536 syncValue : function()
19538 this.editorcore.syncValue();
19541 pushValue : function()
19543 this.editorcore.pushValue();
19547 // hide stuff that is not compatible
19561 * @event specialkey
19565 * @cfg {String} fieldClass @hide
19568 * @cfg {String} focusClass @hide
19571 * @cfg {String} autoCreate @hide
19574 * @cfg {String} inputType @hide
19577 * @cfg {String} invalidClass @hide
19580 * @cfg {String} invalidText @hide
19583 * @cfg {String} msgFx @hide
19586 * @cfg {String} validateOnBlur @hide
19595 Roo.namespace('Roo.bootstrap.htmleditor');
19597 * @class Roo.bootstrap.HtmlEditorToolbar1
19602 new Roo.bootstrap.HtmlEditor({
19605 new Roo.bootstrap.HtmlEditorToolbar1({
19606 disable : { fonts: 1 , format: 1, ..., ... , ...],
19612 * @cfg {Object} disable List of elements to disable..
19613 * @cfg {Array} btns List of additional buttons.
19617 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19620 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19623 Roo.apply(this, config);
19625 // default disabled, based on 'good practice'..
19626 this.disable = this.disable || {};
19627 Roo.applyIf(this.disable, {
19630 specialElements : true
19632 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19634 this.editor = config.editor;
19635 this.editorcore = config.editor.editorcore;
19637 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19639 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19640 // dont call parent... till later.
19642 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19647 editorcore : false,
19652 "h1","h2","h3","h4","h5","h6",
19654 "abbr", "acronym", "address", "cite", "samp", "var",
19658 onRender : function(ct, position)
19660 // Roo.log("Call onRender: " + this.xtype);
19662 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19664 this.el.dom.style.marginBottom = '0';
19666 var editorcore = this.editorcore;
19667 var editor= this.editor;
19670 var btn = function(id,cmd , toggle, handler){
19672 var event = toggle ? 'toggle' : 'click';
19677 xns: Roo.bootstrap,
19680 enableToggle:toggle !== false,
19682 pressed : toggle ? false : null,
19685 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19686 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19695 xns: Roo.bootstrap,
19696 glyphicon : 'font',
19700 xns: Roo.bootstrap,
19704 Roo.each(this.formats, function(f) {
19705 style.menu.items.push({
19707 xns: Roo.bootstrap,
19708 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19713 editorcore.insertTag(this.tagname);
19720 children.push(style);
19723 btn('bold',false,true);
19724 btn('italic',false,true);
19725 btn('align-left', 'justifyleft',true);
19726 btn('align-center', 'justifycenter',true);
19727 btn('align-right' , 'justifyright',true);
19728 btn('link', false, false, function(btn) {
19729 //Roo.log("create link?");
19730 var url = prompt(this.createLinkText, this.defaultLinkValue);
19731 if(url && url != 'http:/'+'/'){
19732 this.editorcore.relayCmd('createlink', url);
19735 btn('list','insertunorderedlist',true);
19736 btn('pencil', false,true, function(btn){
19739 this.toggleSourceEdit(btn.pressed);
19745 xns: Roo.bootstrap,
19750 xns: Roo.bootstrap,
19755 cog.menu.items.push({
19757 xns: Roo.bootstrap,
19758 html : Clean styles,
19763 editorcore.insertTag(this.tagname);
19772 this.xtype = 'NavSimplebar';
19774 for(var i=0;i< children.length;i++) {
19776 this.buttons.add(this.addxtypeChild(children[i]));
19780 editor.on('editorevent', this.updateToolbar, this);
19782 onBtnClick : function(id)
19784 this.editorcore.relayCmd(id);
19785 this.editorcore.focus();
19789 * Protected method that will not generally be called directly. It triggers
19790 * a toolbar update by reading the markup state of the current selection in the editor.
19792 updateToolbar: function(){
19794 if(!this.editorcore.activated){
19795 this.editor.onFirstFocus(); // is this neeed?
19799 var btns = this.buttons;
19800 var doc = this.editorcore.doc;
19801 btns.get('bold').setActive(doc.queryCommandState('bold'));
19802 btns.get('italic').setActive(doc.queryCommandState('italic'));
19803 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19805 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19806 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19807 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19809 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19810 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19813 var ans = this.editorcore.getAllAncestors();
19814 if (this.formatCombo) {
19817 var store = this.formatCombo.store;
19818 this.formatCombo.setValue("");
19819 for (var i =0; i < ans.length;i++) {
19820 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19822 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19830 // hides menus... - so this cant be on a menu...
19831 Roo.bootstrap.MenuMgr.hideAll();
19833 Roo.bootstrap.MenuMgr.hideAll();
19834 //this.editorsyncValue();
19836 onFirstFocus: function() {
19837 this.buttons.each(function(item){
19841 toggleSourceEdit : function(sourceEditMode){
19844 if(sourceEditMode){
19845 Roo.log("disabling buttons");
19846 this.buttons.each( function(item){
19847 if(item.cmd != 'pencil'){
19853 Roo.log("enabling buttons");
19854 if(this.editorcore.initialized){
19855 this.buttons.each( function(item){
19861 Roo.log("calling toggole on editor");
19862 // tell the editor that it's been pressed..
19863 this.editor.toggleSourceEdit(sourceEditMode);
19873 * @class Roo.bootstrap.Table.AbstractSelectionModel
19874 * @extends Roo.util.Observable
19875 * Abstract base class for grid SelectionModels. It provides the interface that should be
19876 * implemented by descendant classes. This class should not be directly instantiated.
19879 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19880 this.locked = false;
19881 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19885 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19886 /** @ignore Called by the grid automatically. Do not call directly. */
19887 init : function(grid){
19893 * Locks the selections.
19896 this.locked = true;
19900 * Unlocks the selections.
19902 unlock : function(){
19903 this.locked = false;
19907 * Returns true if the selections are locked.
19908 * @return {Boolean}
19910 isLocked : function(){
19911 return this.locked;
19915 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19916 * @class Roo.bootstrap.Table.RowSelectionModel
19917 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19918 * It supports multiple selections and keyboard selection/navigation.
19920 * @param {Object} config
19923 Roo.bootstrap.Table.RowSelectionModel = function(config){
19924 Roo.apply(this, config);
19925 this.selections = new Roo.util.MixedCollection(false, function(o){
19930 this.lastActive = false;
19934 * @event selectionchange
19935 * Fires when the selection changes
19936 * @param {SelectionModel} this
19938 "selectionchange" : true,
19940 * @event afterselectionchange
19941 * Fires after the selection changes (eg. by key press or clicking)
19942 * @param {SelectionModel} this
19944 "afterselectionchange" : true,
19946 * @event beforerowselect
19947 * Fires when a row is selected being selected, return false to cancel.
19948 * @param {SelectionModel} this
19949 * @param {Number} rowIndex The selected index
19950 * @param {Boolean} keepExisting False if other selections will be cleared
19952 "beforerowselect" : true,
19955 * Fires when a row is selected.
19956 * @param {SelectionModel} this
19957 * @param {Number} rowIndex The selected index
19958 * @param {Roo.data.Record} r The record
19960 "rowselect" : true,
19962 * @event rowdeselect
19963 * Fires when a row is deselected.
19964 * @param {SelectionModel} this
19965 * @param {Number} rowIndex The selected index
19967 "rowdeselect" : true
19969 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19970 this.locked = false;
19973 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19975 * @cfg {Boolean} singleSelect
19976 * True to allow selection of only one row at a time (defaults to false)
19978 singleSelect : false,
19981 initEvents : function(){
19983 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19984 this.grid.on("mousedown", this.handleMouseDown, this);
19985 }else{ // allow click to work like normal
19986 this.grid.on("rowclick", this.handleDragableRowClick, this);
19989 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19990 "up" : function(e){
19992 this.selectPrevious(e.shiftKey);
19993 }else if(this.last !== false && this.lastActive !== false){
19994 var last = this.last;
19995 this.selectRange(this.last, this.lastActive-1);
19996 this.grid.getView().focusRow(this.lastActive);
19997 if(last !== false){
20001 this.selectFirstRow();
20003 this.fireEvent("afterselectionchange", this);
20005 "down" : function(e){
20007 this.selectNext(e.shiftKey);
20008 }else if(this.last !== false && this.lastActive !== false){
20009 var last = this.last;
20010 this.selectRange(this.last, this.lastActive+1);
20011 this.grid.getView().focusRow(this.lastActive);
20012 if(last !== false){
20016 this.selectFirstRow();
20018 this.fireEvent("afterselectionchange", this);
20023 var view = this.grid.view;
20024 view.on("refresh", this.onRefresh, this);
20025 view.on("rowupdated", this.onRowUpdated, this);
20026 view.on("rowremoved", this.onRemove, this);
20030 onRefresh : function(){
20031 var ds = this.grid.dataSource, i, v = this.grid.view;
20032 var s = this.selections;
20033 s.each(function(r){
20034 if((i = ds.indexOfId(r.id)) != -1){
20043 onRemove : function(v, index, r){
20044 this.selections.remove(r);
20048 onRowUpdated : function(v, index, r){
20049 if(this.isSelected(r)){
20050 v.onRowSelect(index);
20056 * @param {Array} records The records to select
20057 * @param {Boolean} keepExisting (optional) True to keep existing selections
20059 selectRecords : function(records, keepExisting){
20061 this.clearSelections();
20063 var ds = this.grid.dataSource;
20064 for(var i = 0, len = records.length; i < len; i++){
20065 this.selectRow(ds.indexOf(records[i]), true);
20070 * Gets the number of selected rows.
20073 getCount : function(){
20074 return this.selections.length;
20078 * Selects the first row in the grid.
20080 selectFirstRow : function(){
20085 * Select the last row.
20086 * @param {Boolean} keepExisting (optional) True to keep existing selections
20088 selectLastRow : function(keepExisting){
20089 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20093 * Selects the row immediately following the last selected row.
20094 * @param {Boolean} keepExisting (optional) True to keep existing selections
20096 selectNext : function(keepExisting){
20097 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20098 this.selectRow(this.last+1, keepExisting);
20099 this.grid.getView().focusRow(this.last);
20104 * Selects the row that precedes the last selected row.
20105 * @param {Boolean} keepExisting (optional) True to keep existing selections
20107 selectPrevious : function(keepExisting){
20109 this.selectRow(this.last-1, keepExisting);
20110 this.grid.getView().focusRow(this.last);
20115 * Returns the selected records
20116 * @return {Array} Array of selected records
20118 getSelections : function(){
20119 return [].concat(this.selections.items);
20123 * Returns the first selected record.
20126 getSelected : function(){
20127 return this.selections.itemAt(0);
20132 * Clears all selections.
20134 clearSelections : function(fast){
20135 if(this.locked) return;
20137 var ds = this.grid.dataSource;
20138 var s = this.selections;
20139 s.each(function(r){
20140 this.deselectRow(ds.indexOfId(r.id));
20144 this.selections.clear();
20151 * Selects all rows.
20153 selectAll : function(){
20154 if(this.locked) return;
20155 this.selections.clear();
20156 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20157 this.selectRow(i, true);
20162 * Returns True if there is a selection.
20163 * @return {Boolean}
20165 hasSelection : function(){
20166 return this.selections.length > 0;
20170 * Returns True if the specified row is selected.
20171 * @param {Number/Record} record The record or index of the record to check
20172 * @return {Boolean}
20174 isSelected : function(index){
20175 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20176 return (r && this.selections.key(r.id) ? true : false);
20180 * Returns True if the specified record id is selected.
20181 * @param {String} id The id of record to check
20182 * @return {Boolean}
20184 isIdSelected : function(id){
20185 return (this.selections.key(id) ? true : false);
20189 handleMouseDown : function(e, t){
20190 var view = this.grid.getView(), rowIndex;
20191 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20194 if(e.shiftKey && this.last !== false){
20195 var last = this.last;
20196 this.selectRange(last, rowIndex, e.ctrlKey);
20197 this.last = last; // reset the last
20198 view.focusRow(rowIndex);
20200 var isSelected = this.isSelected(rowIndex);
20201 if(e.button !== 0 && isSelected){
20202 view.focusRow(rowIndex);
20203 }else if(e.ctrlKey && isSelected){
20204 this.deselectRow(rowIndex);
20205 }else if(!isSelected){
20206 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20207 view.focusRow(rowIndex);
20210 this.fireEvent("afterselectionchange", this);
20213 handleDragableRowClick : function(grid, rowIndex, e)
20215 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20216 this.selectRow(rowIndex, false);
20217 grid.view.focusRow(rowIndex);
20218 this.fireEvent("afterselectionchange", this);
20223 * Selects multiple rows.
20224 * @param {Array} rows Array of the indexes of the row to select
20225 * @param {Boolean} keepExisting (optional) True to keep existing selections
20227 selectRows : function(rows, keepExisting){
20229 this.clearSelections();
20231 for(var i = 0, len = rows.length; i < len; i++){
20232 this.selectRow(rows[i], true);
20237 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20238 * @param {Number} startRow The index of the first row in the range
20239 * @param {Number} endRow The index of the last row in the range
20240 * @param {Boolean} keepExisting (optional) True to retain existing selections
20242 selectRange : function(startRow, endRow, keepExisting){
20243 if(this.locked) return;
20245 this.clearSelections();
20247 if(startRow <= endRow){
20248 for(var i = startRow; i <= endRow; i++){
20249 this.selectRow(i, true);
20252 for(var i = startRow; i >= endRow; i--){
20253 this.selectRow(i, true);
20259 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20260 * @param {Number} startRow The index of the first row in the range
20261 * @param {Number} endRow The index of the last row in the range
20263 deselectRange : function(startRow, endRow, preventViewNotify){
20264 if(this.locked) return;
20265 for(var i = startRow; i <= endRow; i++){
20266 this.deselectRow(i, preventViewNotify);
20272 * @param {Number} row The index of the row to select
20273 * @param {Boolean} keepExisting (optional) True to keep existing selections
20275 selectRow : function(index, keepExisting, preventViewNotify){
20276 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20277 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20278 if(!keepExisting || this.singleSelect){
20279 this.clearSelections();
20281 var r = this.grid.dataSource.getAt(index);
20282 this.selections.add(r);
20283 this.last = this.lastActive = index;
20284 if(!preventViewNotify){
20285 this.grid.getView().onRowSelect(index);
20287 this.fireEvent("rowselect", this, index, r);
20288 this.fireEvent("selectionchange", this);
20294 * @param {Number} row The index of the row to deselect
20296 deselectRow : function(index, preventViewNotify){
20297 if(this.locked) return;
20298 if(this.last == index){
20301 if(this.lastActive == index){
20302 this.lastActive = false;
20304 var r = this.grid.dataSource.getAt(index);
20305 this.selections.remove(r);
20306 if(!preventViewNotify){
20307 this.grid.getView().onRowDeselect(index);
20309 this.fireEvent("rowdeselect", this, index);
20310 this.fireEvent("selectionchange", this);
20314 restoreLast : function(){
20316 this.last = this._last;
20321 acceptsNav : function(row, col, cm){
20322 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20326 onEditorKey : function(field, e){
20327 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20332 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20334 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20336 }else if(k == e.ENTER && !e.ctrlKey){
20340 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20342 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20344 }else if(k == e.ESC){
20348 g.startEditing(newCell[0], newCell[1]);
20353 * Ext JS Library 1.1.1
20354 * Copyright(c) 2006-2007, Ext JS, LLC.
20356 * Originally Released Under LGPL - original licence link has changed is not relivant.
20359 * <script type="text/javascript">
20363 * @class Roo.bootstrap.PagingToolbar
20365 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20367 * Create a new PagingToolbar
20368 * @param {Object} config The config object
20370 Roo.bootstrap.PagingToolbar = function(config)
20372 // old args format still supported... - xtype is prefered..
20373 // created from xtype...
20374 var ds = config.dataSource;
20375 this.toolbarItems = [];
20376 if (config.items) {
20377 this.toolbarItems = config.items;
20378 // config.items = [];
20381 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20388 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20392 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20394 * @cfg {Roo.data.Store} dataSource
20395 * The underlying data store providing the paged data
20398 * @cfg {String/HTMLElement/Element} container
20399 * container The id or element that will contain the toolbar
20402 * @cfg {Boolean} displayInfo
20403 * True to display the displayMsg (defaults to false)
20406 * @cfg {Number} pageSize
20407 * The number of records to display per page (defaults to 20)
20411 * @cfg {String} displayMsg
20412 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20414 displayMsg : 'Displaying {0} - {1} of {2}',
20416 * @cfg {String} emptyMsg
20417 * The message to display when no records are found (defaults to "No data to display")
20419 emptyMsg : 'No data to display',
20421 * Customizable piece of the default paging text (defaults to "Page")
20424 beforePageText : "Page",
20426 * Customizable piece of the default paging text (defaults to "of %0")
20429 afterPageText : "of {0}",
20431 * Customizable piece of the default paging text (defaults to "First Page")
20434 firstText : "First Page",
20436 * Customizable piece of the default paging text (defaults to "Previous Page")
20439 prevText : "Previous Page",
20441 * Customizable piece of the default paging text (defaults to "Next Page")
20444 nextText : "Next Page",
20446 * Customizable piece of the default paging text (defaults to "Last Page")
20449 lastText : "Last Page",
20451 * Customizable piece of the default paging text (defaults to "Refresh")
20454 refreshText : "Refresh",
20458 onRender : function(ct, position)
20460 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20461 this.navgroup.parentId = this.id;
20462 this.navgroup.onRender(this.el, null);
20463 // add the buttons to the navgroup
20465 if(this.displayInfo){
20466 Roo.log(this.el.select('ul.navbar-nav',true).first());
20467 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20468 this.displayEl = this.el.select('.x-paging-info', true).first();
20469 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20470 // this.displayEl = navel.el.select('span',true).first();
20476 Roo.each(_this.buttons, function(e){
20477 Roo.factory(e).onRender(_this.el, null);
20481 Roo.each(_this.toolbarItems, function(e) {
20482 _this.navgroup.addItem(e);
20486 this.first = this.navgroup.addItem({
20487 tooltip: this.firstText,
20489 icon : 'fa fa-backward',
20491 preventDefault: true,
20492 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20495 this.prev = this.navgroup.addItem({
20496 tooltip: this.prevText,
20498 icon : 'fa fa-step-backward',
20500 preventDefault: true,
20501 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20503 //this.addSeparator();
20506 var field = this.navgroup.addItem( {
20508 cls : 'x-paging-position',
20510 html : this.beforePageText +
20511 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20512 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20515 this.field = field.el.select('input', true).first();
20516 this.field.on("keydown", this.onPagingKeydown, this);
20517 this.field.on("focus", function(){this.dom.select();});
20520 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20521 //this.field.setHeight(18);
20522 //this.addSeparator();
20523 this.next = this.navgroup.addItem({
20524 tooltip: this.nextText,
20526 html : ' <i class="fa fa-step-forward">',
20528 preventDefault: true,
20529 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20531 this.last = this.navgroup.addItem({
20532 tooltip: this.lastText,
20533 icon : 'fa fa-forward',
20536 preventDefault: true,
20537 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20539 //this.addSeparator();
20540 this.loading = this.navgroup.addItem({
20541 tooltip: this.refreshText,
20542 icon: 'fa fa-refresh',
20543 preventDefault: true,
20544 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20550 updateInfo : function(){
20551 if(this.displayEl){
20552 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20553 var msg = count == 0 ?
20557 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20559 this.displayEl.update(msg);
20564 onLoad : function(ds, r, o){
20565 this.cursor = o.params ? o.params.start : 0;
20566 var d = this.getPageData(),
20570 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20571 this.field.dom.value = ap;
20572 this.first.setDisabled(ap == 1);
20573 this.prev.setDisabled(ap == 1);
20574 this.next.setDisabled(ap == ps);
20575 this.last.setDisabled(ap == ps);
20576 this.loading.enable();
20581 getPageData : function(){
20582 var total = this.ds.getTotalCount();
20585 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20586 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20591 onLoadError : function(){
20592 this.loading.enable();
20596 onPagingKeydown : function(e){
20597 var k = e.getKey();
20598 var d = this.getPageData();
20600 var v = this.field.dom.value, pageNum;
20601 if(!v || isNaN(pageNum = parseInt(v, 10))){
20602 this.field.dom.value = d.activePage;
20605 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20606 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20609 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))
20611 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20612 this.field.dom.value = pageNum;
20613 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20616 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20618 var v = this.field.dom.value, pageNum;
20619 var increment = (e.shiftKey) ? 10 : 1;
20620 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20622 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20623 this.field.dom.value = d.activePage;
20626 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20628 this.field.dom.value = parseInt(v, 10) + increment;
20629 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20630 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20637 beforeLoad : function(){
20639 this.loading.disable();
20644 onClick : function(which){
20653 ds.load({params:{start: 0, limit: this.pageSize}});
20656 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20659 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20662 var total = ds.getTotalCount();
20663 var extra = total % this.pageSize;
20664 var lastStart = extra ? (total - extra) : total-this.pageSize;
20665 ds.load({params:{start: lastStart, limit: this.pageSize}});
20668 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20674 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20675 * @param {Roo.data.Store} store The data store to unbind
20677 unbind : function(ds){
20678 ds.un("beforeload", this.beforeLoad, this);
20679 ds.un("load", this.onLoad, this);
20680 ds.un("loadexception", this.onLoadError, this);
20681 ds.un("remove", this.updateInfo, this);
20682 ds.un("add", this.updateInfo, this);
20683 this.ds = undefined;
20687 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20688 * @param {Roo.data.Store} store The data store to bind
20690 bind : function(ds){
20691 ds.on("beforeload", this.beforeLoad, this);
20692 ds.on("load", this.onLoad, this);
20693 ds.on("loadexception", this.onLoadError, this);
20694 ds.on("remove", this.updateInfo, this);
20695 ds.on("add", this.updateInfo, this);
20706 * @class Roo.bootstrap.MessageBar
20707 * @extends Roo.bootstrap.Component
20708 * Bootstrap MessageBar class
20709 * @cfg {String} html contents of the MessageBar
20710 * @cfg {String} weight (info | success | warning | danger) default info
20711 * @cfg {String} beforeClass insert the bar before the given class
20712 * @cfg {Boolean} closable (true | false) default false
20713 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20716 * Create a new Element
20717 * @param {Object} config The config object
20720 Roo.bootstrap.MessageBar = function(config){
20721 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20724 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20730 beforeClass: 'bootstrap-sticky-wrap',
20732 getAutoCreate : function(){
20736 cls: 'alert alert-dismissable alert-' + this.weight,
20741 html: this.html || ''
20747 cfg.cls += ' alert-messages-fixed';
20761 onRender : function(ct, position)
20763 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20766 var cfg = Roo.apply({}, this.getAutoCreate());
20770 cfg.cls += ' ' + this.cls;
20773 cfg.style = this.style;
20775 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20777 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20780 this.el.select('>button.close').on('click', this.hide, this);
20786 if (!this.rendered) {
20792 this.fireEvent('show', this);
20798 if (!this.rendered) {
20804 this.fireEvent('hide', this);
20807 update : function()
20809 // var e = this.el.dom.firstChild;
20811 // if(this.closable){
20812 // e = e.nextSibling;
20815 // e.data = this.html || '';
20817 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20833 * @class Roo.bootstrap.Graph
20834 * @extends Roo.bootstrap.Component
20835 * Bootstrap Graph class
20839 @cfg {String} graphtype bar | vbar | pie
20840 @cfg {number} g_x coodinator | centre x (pie)
20841 @cfg {number} g_y coodinator | centre y (pie)
20842 @cfg {number} g_r radius (pie)
20843 @cfg {number} g_height height of the chart (respected by all elements in the set)
20844 @cfg {number} g_width width of the chart (respected by all elements in the set)
20845 @cfg {Object} title The title of the chart
20848 -opts (object) options for the chart
20850 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20851 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20853 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.
20854 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20856 o stretch (boolean)
20858 -opts (object) options for the pie
20861 o startAngle (number)
20862 o endAngle (number)
20866 * Create a new Input
20867 * @param {Object} config The config object
20870 Roo.bootstrap.Graph = function(config){
20871 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20877 * The img click event for the img.
20878 * @param {Roo.EventObject} e
20884 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20895 //g_colors: this.colors,
20902 getAutoCreate : function(){
20913 onRender : function(ct,position){
20914 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20915 this.raphael = Raphael(this.el.dom);
20917 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20918 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20919 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20920 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20922 r.text(160, 10, "Single Series Chart").attr(txtattr);
20923 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20924 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20925 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20927 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20928 r.barchart(330, 10, 300, 220, data1);
20929 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20930 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20933 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20934 // r.barchart(30, 30, 560, 250, xdata, {
20935 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20936 // axis : "0 0 1 1",
20937 // axisxlabels : xdata
20938 // //yvalues : cols,
20941 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20943 // this.load(null,xdata,{
20944 // axis : "0 0 1 1",
20945 // axisxlabels : xdata
20950 load : function(graphtype,xdata,opts){
20951 this.raphael.clear();
20953 graphtype = this.graphtype;
20958 var r = this.raphael,
20959 fin = function () {
20960 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20962 fout = function () {
20963 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20965 pfin = function() {
20966 this.sector.stop();
20967 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20970 this.label[0].stop();
20971 this.label[0].attr({ r: 7.5 });
20972 this.label[1].attr({ "font-weight": 800 });
20975 pfout = function() {
20976 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20979 this.label[0].animate({ r: 5 }, 500, "bounce");
20980 this.label[1].attr({ "font-weight": 400 });
20986 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20989 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20992 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20993 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20995 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21002 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21007 setTitle: function(o)
21012 initEvents: function() {
21015 this.el.on('click', this.onClick, this);
21019 onClick : function(e)
21021 Roo.log('img onclick');
21022 this.fireEvent('click', this, e);
21034 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21037 * @class Roo.bootstrap.dash.NumberBox
21038 * @extends Roo.bootstrap.Component
21039 * Bootstrap NumberBox class
21040 * @cfg {String} headline Box headline
21041 * @cfg {String} content Box content
21042 * @cfg {String} icon Box icon
21043 * @cfg {String} footer Footer text
21044 * @cfg {String} fhref Footer href
21047 * Create a new NumberBox
21048 * @param {Object} config The config object
21052 Roo.bootstrap.dash.NumberBox = function(config){
21053 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21057 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21066 getAutoCreate : function(){
21070 cls : 'small-box ',
21078 cls : 'roo-headline',
21079 html : this.headline
21083 cls : 'roo-content',
21084 html : this.content
21098 cls : 'ion ' + this.icon
21107 cls : 'small-box-footer',
21108 href : this.fhref || '#',
21112 cfg.cn.push(footer);
21119 onRender : function(ct,position){
21120 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21127 setHeadline: function (value)
21129 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21132 setFooter: function (value, href)
21134 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21137 this.el.select('a.small-box-footer',true).first().attr('href', href);
21142 setContent: function (value)
21144 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21147 initEvents: function()
21161 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21164 * @class Roo.bootstrap.dash.TabBox
21165 * @extends Roo.bootstrap.Component
21166 * Bootstrap TabBox class
21167 * @cfg {String} title Title of the TabBox
21168 * @cfg {String} icon Icon of the TabBox
21169 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21170 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21173 * Create a new TabBox
21174 * @param {Object} config The config object
21178 Roo.bootstrap.dash.TabBox = function(config){
21179 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21184 * When a pane is added
21185 * @param {Roo.bootstrap.dash.TabPane} pane
21189 * @event activatepane
21190 * When a pane is activated
21191 * @param {Roo.bootstrap.dash.TabPane} pane
21193 "activatepane" : true
21201 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21206 tabScrollable : false,
21208 getChildContainer : function()
21210 return this.el.select('.tab-content', true).first();
21213 getAutoCreate : function(){
21217 cls: 'pull-left header',
21225 cls: 'fa ' + this.icon
21231 cls: 'nav nav-tabs pull-right',
21237 if(this.tabScrollable){
21244 cls: 'nav nav-tabs pull-right',
21255 cls: 'nav-tabs-custom',
21260 cls: 'tab-content no-padding',
21268 initEvents : function()
21270 //Roo.log('add add pane handler');
21271 this.on('addpane', this.onAddPane, this);
21274 * Updates the box title
21275 * @param {String} html to set the title to.
21277 setTitle : function(value)
21279 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21281 onAddPane : function(pane)
21283 this.panes.push(pane);
21284 //Roo.log('addpane');
21286 // tabs are rendere left to right..
21287 if(!this.showtabs){
21291 var ctr = this.el.select('.nav-tabs', true).first();
21294 var existing = ctr.select('.nav-tab',true);
21295 var qty = existing.getCount();;
21298 var tab = ctr.createChild({
21300 cls : 'nav-tab' + (qty ? '' : ' active'),
21308 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21311 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21313 pane.el.addClass('active');
21318 onTabClick : function(ev,un,ob,pane)
21320 //Roo.log('tab - prev default');
21321 ev.preventDefault();
21324 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21325 pane.tab.addClass('active');
21326 //Roo.log(pane.title);
21327 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21328 // technically we should have a deactivate event.. but maybe add later.
21329 // and it should not de-activate the selected tab...
21330 this.fireEvent('activatepane', pane);
21331 pane.el.addClass('active');
21332 pane.fireEvent('activate');
21337 getActivePane : function()
21340 Roo.each(this.panes, function(p) {
21341 if(p.el.hasClass('active')){
21362 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21364 * @class Roo.bootstrap.TabPane
21365 * @extends Roo.bootstrap.Component
21366 * Bootstrap TabPane class
21367 * @cfg {Boolean} active (false | true) Default false
21368 * @cfg {String} title title of panel
21372 * Create a new TabPane
21373 * @param {Object} config The config object
21376 Roo.bootstrap.dash.TabPane = function(config){
21377 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21383 * When a pane is activated
21384 * @param {Roo.bootstrap.dash.TabPane} pane
21391 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21396 // the tabBox that this is attached to.
21399 getAutoCreate : function()
21407 cfg.cls += ' active';
21412 initEvents : function()
21414 //Roo.log('trigger add pane handler');
21415 this.parent().fireEvent('addpane', this)
21419 * Updates the tab title
21420 * @param {String} html to set the title to.
21422 setTitle: function(str)
21428 this.tab.select('a', true).first().dom.innerHTML = str;
21445 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21448 * @class Roo.bootstrap.menu.Menu
21449 * @extends Roo.bootstrap.Component
21450 * Bootstrap Menu class - container for Menu
21451 * @cfg {String} html Text of the menu
21452 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21453 * @cfg {String} icon Font awesome icon
21454 * @cfg {String} pos Menu align to (top | bottom) default bottom
21458 * Create a new Menu
21459 * @param {Object} config The config object
21463 Roo.bootstrap.menu.Menu = function(config){
21464 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21468 * @event beforeshow
21469 * Fires before this menu is displayed
21470 * @param {Roo.bootstrap.menu.Menu} this
21474 * @event beforehide
21475 * Fires before this menu is hidden
21476 * @param {Roo.bootstrap.menu.Menu} this
21481 * Fires after this menu is displayed
21482 * @param {Roo.bootstrap.menu.Menu} this
21487 * Fires after this menu is hidden
21488 * @param {Roo.bootstrap.menu.Menu} this
21493 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21494 * @param {Roo.bootstrap.menu.Menu} this
21495 * @param {Roo.EventObject} e
21502 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21506 weight : 'default',
21511 getChildContainer : function() {
21512 if(this.isSubMenu){
21516 return this.el.select('ul.dropdown-menu', true).first();
21519 getAutoCreate : function()
21524 cls : 'roo-menu-text',
21532 cls : 'fa ' + this.icon
21543 cls : 'dropdown-button btn btn-' + this.weight,
21548 cls : 'dropdown-toggle btn btn-' + this.weight,
21558 cls : 'dropdown-menu'
21564 if(this.pos == 'top'){
21565 cfg.cls += ' dropup';
21568 if(this.isSubMenu){
21571 cls : 'dropdown-menu'
21578 onRender : function(ct, position)
21580 this.isSubMenu = ct.hasClass('dropdown-submenu');
21582 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21585 initEvents : function()
21587 if(this.isSubMenu){
21591 this.hidden = true;
21593 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21594 this.triggerEl.on('click', this.onTriggerPress, this);
21596 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21597 this.buttonEl.on('click', this.onClick, this);
21603 if(this.isSubMenu){
21607 return this.el.select('ul.dropdown-menu', true).first();
21610 onClick : function(e)
21612 this.fireEvent("click", this, e);
21615 onTriggerPress : function(e)
21617 if (this.isVisible()) {
21624 isVisible : function(){
21625 return !this.hidden;
21630 this.fireEvent("beforeshow", this);
21632 this.hidden = false;
21633 this.el.addClass('open');
21635 Roo.get(document).on("mouseup", this.onMouseUp, this);
21637 this.fireEvent("show", this);
21644 this.fireEvent("beforehide", this);
21646 this.hidden = true;
21647 this.el.removeClass('open');
21649 Roo.get(document).un("mouseup", this.onMouseUp);
21651 this.fireEvent("hide", this);
21654 onMouseUp : function()
21668 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21671 * @class Roo.bootstrap.menu.Item
21672 * @extends Roo.bootstrap.Component
21673 * Bootstrap MenuItem class
21674 * @cfg {Boolean} submenu (true | false) default false
21675 * @cfg {String} html text of the item
21676 * @cfg {String} href the link
21677 * @cfg {Boolean} disable (true | false) default false
21678 * @cfg {Boolean} preventDefault (true | false) default true
21679 * @cfg {String} icon Font awesome icon
21680 * @cfg {String} pos Submenu align to (left | right) default right
21684 * Create a new Item
21685 * @param {Object} config The config object
21689 Roo.bootstrap.menu.Item = function(config){
21690 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21694 * Fires when the mouse is hovering over this menu
21695 * @param {Roo.bootstrap.menu.Item} this
21696 * @param {Roo.EventObject} e
21701 * Fires when the mouse exits this menu
21702 * @param {Roo.bootstrap.menu.Item} this
21703 * @param {Roo.EventObject} e
21709 * The raw click event for the entire grid.
21710 * @param {Roo.EventObject} e
21716 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21721 preventDefault: true,
21726 getAutoCreate : function()
21731 cls : 'roo-menu-item-text',
21739 cls : 'fa ' + this.icon
21748 href : this.href || '#',
21755 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21759 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21761 if(this.pos == 'left'){
21762 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21769 initEvents : function()
21771 this.el.on('mouseover', this.onMouseOver, this);
21772 this.el.on('mouseout', this.onMouseOut, this);
21774 this.el.select('a', true).first().on('click', this.onClick, this);
21778 onClick : function(e)
21780 if(this.preventDefault){
21781 e.preventDefault();
21784 this.fireEvent("click", this, e);
21787 onMouseOver : function(e)
21789 if(this.submenu && this.pos == 'left'){
21790 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21793 this.fireEvent("mouseover", this, e);
21796 onMouseOut : function(e)
21798 this.fireEvent("mouseout", this, e);
21810 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21813 * @class Roo.bootstrap.menu.Separator
21814 * @extends Roo.bootstrap.Component
21815 * Bootstrap Separator class
21818 * Create a new Separator
21819 * @param {Object} config The config object
21823 Roo.bootstrap.menu.Separator = function(config){
21824 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21827 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21829 getAutoCreate : function(){
21850 * @class Roo.bootstrap.Tooltip
21851 * Bootstrap Tooltip class
21852 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21853 * to determine which dom element triggers the tooltip.
21855 * It needs to add support for additional attributes like tooltip-position
21858 * Create a new Toolti
21859 * @param {Object} config The config object
21862 Roo.bootstrap.Tooltip = function(config){
21863 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21866 Roo.apply(Roo.bootstrap.Tooltip, {
21868 * @function init initialize tooltip monitoring.
21872 currentTip : false,
21873 currentRegion : false,
21879 Roo.get(document).on('mouseover', this.enter ,this);
21880 Roo.get(document).on('mouseout', this.leave, this);
21883 this.currentTip = new Roo.bootstrap.Tooltip();
21886 enter : function(ev)
21888 var dom = ev.getTarget();
21890 //Roo.log(['enter',dom]);
21891 var el = Roo.fly(dom);
21892 if (this.currentEl) {
21894 //Roo.log(this.currentEl);
21895 //Roo.log(this.currentEl.contains(dom));
21896 if (this.currentEl == el) {
21899 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21907 if (this.currentTip.el) {
21908 this.currentTip.el.hide(); // force hiding...
21913 // you can not look for children, as if el is the body.. then everythign is the child..
21914 if (!el.attr('tooltip')) { //
21915 if (!el.select("[tooltip]").elements.length) {
21918 // is the mouse over this child...?
21919 bindEl = el.select("[tooltip]").first();
21920 var xy = ev.getXY();
21921 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21922 //Roo.log("not in region.");
21925 //Roo.log("child element over..");
21928 this.currentEl = bindEl;
21929 this.currentTip.bind(bindEl);
21930 this.currentRegion = Roo.lib.Region.getRegion(dom);
21931 this.currentTip.enter();
21934 leave : function(ev)
21936 var dom = ev.getTarget();
21937 //Roo.log(['leave',dom]);
21938 if (!this.currentEl) {
21943 if (dom != this.currentEl.dom) {
21946 var xy = ev.getXY();
21947 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21950 // only activate leave if mouse cursor is outside... bounding box..
21955 if (this.currentTip) {
21956 this.currentTip.leave();
21958 //Roo.log('clear currentEl');
21959 this.currentEl = false;
21964 'left' : ['r-l', [-2,0], 'right'],
21965 'right' : ['l-r', [2,0], 'left'],
21966 'bottom' : ['t-b', [0,2], 'top'],
21967 'top' : [ 'b-t', [0,-2], 'bottom']
21973 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21978 delay : null, // can be { show : 300 , hide: 500}
21982 hoverState : null, //???
21984 placement : 'bottom',
21986 getAutoCreate : function(){
21993 cls : 'tooltip-arrow'
21996 cls : 'tooltip-inner'
22003 bind : function(el)
22009 enter : function () {
22011 if (this.timeout != null) {
22012 clearTimeout(this.timeout);
22015 this.hoverState = 'in';
22016 //Roo.log("enter - show");
22017 if (!this.delay || !this.delay.show) {
22022 this.timeout = setTimeout(function () {
22023 if (_t.hoverState == 'in') {
22026 }, this.delay.show);
22030 clearTimeout(this.timeout);
22032 this.hoverState = 'out';
22033 if (!this.delay || !this.delay.hide) {
22039 this.timeout = setTimeout(function () {
22040 //Roo.log("leave - timeout");
22042 if (_t.hoverState == 'out') {
22044 Roo.bootstrap.Tooltip.currentEl = false;
22052 this.render(document.body);
22055 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22057 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22059 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22061 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22063 var placement = typeof this.placement == 'function' ?
22064 this.placement.call(this, this.el, on_el) :
22067 var autoToken = /\s?auto?\s?/i;
22068 var autoPlace = autoToken.test(placement);
22070 placement = placement.replace(autoToken, '') || 'top';
22074 //this.el.setXY([0,0]);
22076 //this.el.dom.style.display='block';
22077 this.el.addClass(placement);
22079 //this.el.appendTo(on_el);
22081 var p = this.getPosition();
22082 var box = this.el.getBox();
22087 var align = Roo.bootstrap.Tooltip.alignment[placement];
22088 this.el.alignTo(this.bindEl, align[0],align[1]);
22089 //var arrow = this.el.select('.arrow',true).first();
22090 //arrow.set(align[2],
22092 this.el.addClass('in fade');
22093 this.hoverState = null;
22095 if (this.el.hasClass('fade')) {
22106 //this.el.setXY([0,0]);
22107 this.el.removeClass('in');
22123 * @class Roo.bootstrap.LocationPicker
22124 * @extends Roo.bootstrap.Component
22125 * Bootstrap LocationPicker class
22126 * @cfg {Number} latitude Position when init default 0
22127 * @cfg {Number} longitude Position when init default 0
22128 * @cfg {Number} zoom default 15
22129 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22130 * @cfg {Boolean} mapTypeControl default false
22131 * @cfg {Boolean} disableDoubleClickZoom default false
22132 * @cfg {Boolean} scrollwheel default true
22133 * @cfg {Boolean} streetViewControl default false
22134 * @cfg {Number} radius default 0
22135 * @cfg {String} locationName
22136 * @cfg {Boolean} draggable default true
22137 * @cfg {Boolean} enableAutocomplete default false
22138 * @cfg {Boolean} enableReverseGeocode default true
22139 * @cfg {String} markerTitle
22142 * Create a new LocationPicker
22143 * @param {Object} config The config object
22147 Roo.bootstrap.LocationPicker = function(config){
22149 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22154 * Fires when the picker initialized.
22155 * @param {Roo.bootstrap.LocationPicker} this
22156 * @param {Google Location} location
22160 * @event positionchanged
22161 * Fires when the picker position changed.
22162 * @param {Roo.bootstrap.LocationPicker} this
22163 * @param {Google Location} location
22165 positionchanged : true,
22168 * Fires when the map resize.
22169 * @param {Roo.bootstrap.LocationPicker} this
22174 * Fires when the map show.
22175 * @param {Roo.bootstrap.LocationPicker} this
22180 * Fires when the map hide.
22181 * @param {Roo.bootstrap.LocationPicker} this
22186 * Fires when click the map.
22187 * @param {Roo.bootstrap.LocationPicker} this
22188 * @param {Map event} e
22192 * @event mapRightClick
22193 * Fires when right click the map.
22194 * @param {Roo.bootstrap.LocationPicker} this
22195 * @param {Map event} e
22197 mapRightClick : true,
22199 * @event markerClick
22200 * Fires when click the marker.
22201 * @param {Roo.bootstrap.LocationPicker} this
22202 * @param {Map event} e
22204 markerClick : true,
22206 * @event markerRightClick
22207 * Fires when right click the marker.
22208 * @param {Roo.bootstrap.LocationPicker} this
22209 * @param {Map event} e
22211 markerRightClick : true,
22213 * @event OverlayViewDraw
22214 * Fires when OverlayView Draw
22215 * @param {Roo.bootstrap.LocationPicker} this
22217 OverlayViewDraw : true,
22219 * @event OverlayViewOnAdd
22220 * Fires when OverlayView Draw
22221 * @param {Roo.bootstrap.LocationPicker} this
22223 OverlayViewOnAdd : true,
22225 * @event OverlayViewOnRemove
22226 * Fires when OverlayView Draw
22227 * @param {Roo.bootstrap.LocationPicker} this
22229 OverlayViewOnRemove : true,
22231 * @event OverlayViewShow
22232 * Fires when OverlayView Draw
22233 * @param {Roo.bootstrap.LocationPicker} this
22234 * @param {Pixel} cpx
22236 OverlayViewShow : true,
22238 * @event OverlayViewHide
22239 * Fires when OverlayView Draw
22240 * @param {Roo.bootstrap.LocationPicker} this
22242 OverlayViewHide : true
22247 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22249 gMapContext: false,
22255 mapTypeControl: false,
22256 disableDoubleClickZoom: false,
22258 streetViewControl: false,
22262 enableAutocomplete: false,
22263 enableReverseGeocode: true,
22266 getAutoCreate: function()
22271 cls: 'roo-location-picker'
22277 initEvents: function(ct, position)
22279 if(!this.el.getWidth() || this.isApplied()){
22283 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22288 initial: function()
22290 if(!this.mapTypeId){
22291 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22294 this.gMapContext = this.GMapContext();
22296 this.initOverlayView();
22298 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22302 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22303 _this.setPosition(_this.gMapContext.marker.position);
22306 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22307 _this.fireEvent('mapClick', this, event);
22311 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22312 _this.fireEvent('mapRightClick', this, event);
22316 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22317 _this.fireEvent('markerClick', this, event);
22321 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22322 _this.fireEvent('markerRightClick', this, event);
22326 this.setPosition(this.gMapContext.location);
22328 this.fireEvent('initial', this, this.gMapContext.location);
22331 initOverlayView: function()
22335 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22339 _this.fireEvent('OverlayViewDraw', _this);
22344 _this.fireEvent('OverlayViewOnAdd', _this);
22347 onRemove: function()
22349 _this.fireEvent('OverlayViewOnRemove', _this);
22352 show: function(cpx)
22354 _this.fireEvent('OverlayViewShow', _this, cpx);
22359 _this.fireEvent('OverlayViewHide', _this);
22365 fromLatLngToContainerPixel: function(event)
22367 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22370 isApplied: function()
22372 return this.getGmapContext() == false ? false : true;
22375 getGmapContext: function()
22377 return this.gMapContext
22380 GMapContext: function()
22382 var position = new google.maps.LatLng(this.latitude, this.longitude);
22384 var _map = new google.maps.Map(this.el.dom, {
22387 mapTypeId: this.mapTypeId,
22388 mapTypeControl: this.mapTypeControl,
22389 disableDoubleClickZoom: this.disableDoubleClickZoom,
22390 scrollwheel: this.scrollwheel,
22391 streetViewControl: this.streetViewControl,
22392 locationName: this.locationName,
22393 draggable: this.draggable,
22394 enableAutocomplete: this.enableAutocomplete,
22395 enableReverseGeocode: this.enableReverseGeocode
22398 var _marker = new google.maps.Marker({
22399 position: position,
22401 title: this.markerTitle,
22402 draggable: this.draggable
22409 location: position,
22410 radius: this.radius,
22411 locationName: this.locationName,
22412 addressComponents: {
22413 formatted_address: null,
22414 addressLine1: null,
22415 addressLine2: null,
22417 streetNumber: null,
22421 stateOrProvince: null
22424 domContainer: this.el.dom,
22425 geodecoder: new google.maps.Geocoder()
22429 drawCircle: function(center, radius, options)
22431 if (this.gMapContext.circle != null) {
22432 this.gMapContext.circle.setMap(null);
22436 options = Roo.apply({}, options, {
22437 strokeColor: "#0000FF",
22438 strokeOpacity: .35,
22440 fillColor: "#0000FF",
22444 options.map = this.gMapContext.map;
22445 options.radius = radius;
22446 options.center = center;
22447 this.gMapContext.circle = new google.maps.Circle(options);
22448 return this.gMapContext.circle;
22454 setPosition: function(location)
22456 this.gMapContext.location = location;
22457 this.gMapContext.marker.setPosition(location);
22458 this.gMapContext.map.panTo(location);
22459 this.drawCircle(location, this.gMapContext.radius, {});
22463 if (this.gMapContext.settings.enableReverseGeocode) {
22464 this.gMapContext.geodecoder.geocode({
22465 latLng: this.gMapContext.location
22466 }, function(results, status) {
22468 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22469 _this.gMapContext.locationName = results[0].formatted_address;
22470 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22472 _this.fireEvent('positionchanged', this, location);
22479 this.fireEvent('positionchanged', this, location);
22484 google.maps.event.trigger(this.gMapContext.map, "resize");
22486 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22488 this.fireEvent('resize', this);
22491 setPositionByLatLng: function(latitude, longitude)
22493 this.setPosition(new google.maps.LatLng(latitude, longitude));
22496 getCurrentPosition: function()
22499 latitude: this.gMapContext.location.lat(),
22500 longitude: this.gMapContext.location.lng()
22504 getAddressName: function()
22506 return this.gMapContext.locationName;
22509 getAddressComponents: function()
22511 return this.gMapContext.addressComponents;
22514 address_component_from_google_geocode: function(address_components)
22518 for (var i = 0; i < address_components.length; i++) {
22519 var component = address_components[i];
22520 if (component.types.indexOf("postal_code") >= 0) {
22521 result.postalCode = component.short_name;
22522 } else if (component.types.indexOf("street_number") >= 0) {
22523 result.streetNumber = component.short_name;
22524 } else if (component.types.indexOf("route") >= 0) {
22525 result.streetName = component.short_name;
22526 } else if (component.types.indexOf("neighborhood") >= 0) {
22527 result.city = component.short_name;
22528 } else if (component.types.indexOf("locality") >= 0) {
22529 result.city = component.short_name;
22530 } else if (component.types.indexOf("sublocality") >= 0) {
22531 result.district = component.short_name;
22532 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22533 result.stateOrProvince = component.short_name;
22534 } else if (component.types.indexOf("country") >= 0) {
22535 result.country = component.short_name;
22539 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22540 result.addressLine2 = "";
22544 setZoomLevel: function(zoom)
22546 this.gMapContext.map.setZoom(zoom);
22559 this.fireEvent('show', this);
22570 this.fireEvent('hide', this);
22575 Roo.apply(Roo.bootstrap.LocationPicker, {
22577 OverlayView : function(map, options)
22579 options = options || {};
22593 * @class Roo.bootstrap.Alert
22594 * @extends Roo.bootstrap.Component
22595 * Bootstrap Alert class
22596 * @cfg {String} title The title of alert
22597 * @cfg {String} html The content of alert
22598 * @cfg {String} weight ( success | info | warning | danger )
22599 * @cfg {String} faicon font-awesomeicon
22602 * Create a new alert
22603 * @param {Object} config The config object
22607 Roo.bootstrap.Alert = function(config){
22608 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22612 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22619 getAutoCreate : function()
22628 cls : 'roo-alert-icon'
22633 cls : 'roo-alert-title',
22638 cls : 'roo-alert-text',
22645 cfg.cn[0].cls += ' fa ' + this.faicon;
22649 cfg.cls += ' alert-' + this.weight;
22655 initEvents: function()
22657 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22660 setTitle : function(str)
22662 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22665 setText : function(str)
22667 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22670 setWeight : function(weight)
22673 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22676 this.weight = weight;
22678 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22681 setIcon : function(icon)
22684 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22689 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);