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.EventObject} e
1980 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1984 preventDefault: true,
1985 isContainer : false,
1987 getAutoCreate : function(){
1989 if(this.isContainer){
1992 cls: 'dropdown-menu-item'
1998 cls: 'dropdown-menu-item',
2007 if (this.parent().type == 'treeview') {
2008 cfg.cls = 'treeview-menu';
2011 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2012 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2016 initEvents: function() {
2018 //this.el.select('a').on('click', this.onClick, this);
2021 onClick : function(e)
2023 Roo.log('item on click ');
2024 //if(this.preventDefault){
2025 // e.preventDefault();
2027 //this.parent().hideMenuItems();
2029 this.fireEvent('click', this, e);
2048 * @class Roo.bootstrap.MenuSeparator
2049 * @extends Roo.bootstrap.Component
2050 * Bootstrap MenuSeparator class
2053 * Create a new MenuItem
2054 * @param {Object} config The config object
2058 Roo.bootstrap.MenuSeparator = function(config){
2059 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2062 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2064 getAutoCreate : function(){
2083 * @class Roo.bootstrap.Modal
2084 * @extends Roo.bootstrap.Component
2085 * Bootstrap Modal class
2086 * @cfg {String} title Title of dialog
2087 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2088 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2089 * @cfg {Boolean} specificTitle default false
2090 * @cfg {Array} buttons Array of buttons or standard button set..
2091 * @cfg {String} buttonPosition (left|right|center) default right
2092 * @cfg {Boolean} animate default true
2093 * @cfg {Boolean} allow_close default true
2096 * Create a new Modal Dialog
2097 * @param {Object} config The config object
2100 Roo.bootstrap.Modal = function(config){
2101 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2106 * The raw btnclick event for the button
2107 * @param {Roo.EventObject} e
2111 this.buttons = this.buttons || [];
2114 this.tmpl = Roo.factory(this.tmpl);
2119 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2121 title : 'test dialog',
2131 specificTitle: false,
2133 buttonPosition: 'right',
2147 onRender : function(ct, position)
2149 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2152 var cfg = Roo.apply({}, this.getAutoCreate());
2155 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2157 //if (!cfg.name.length) {
2161 cfg.cls += ' ' + this.cls;
2164 cfg.style = this.style;
2166 this.el = Roo.get(document.body).createChild(cfg, position);
2168 //var type = this.el.dom.type;
2173 if(this.tabIndex !== undefined){
2174 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2178 this.bodyEl = this.el.select('.modal-body',true).first();
2179 this.closeEl = this.el.select('.modal-header .close', true).first();
2180 this.footerEl = this.el.select('.modal-footer',true).first();
2181 this.titleEl = this.el.select('.modal-title',true).first();
2185 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2186 this.maskEl.enableDisplayMode("block");
2188 //this.el.addClass("x-dlg-modal");
2190 if (this.buttons.length) {
2191 Roo.each(this.buttons, function(bb) {
2192 b = Roo.apply({}, bb);
2193 b.xns = b.xns || Roo.bootstrap;
2194 b.xtype = b.xtype || 'Button';
2195 if (typeof(b.listeners) == 'undefined') {
2196 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2199 var btn = Roo.factory(b);
2201 btn.onRender(this.el.select('.modal-footer div').first());
2205 // render the children.
2208 if(typeof(this.items) != 'undefined'){
2209 var items = this.items;
2212 for(var i =0;i < items.length;i++) {
2213 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2217 this.items = nitems;
2219 // where are these used - they used to be body/close/footer
2223 //this.el.addClass([this.fieldClass, this.cls]);
2226 getAutoCreate : function(){
2231 html : this.html || ''
2236 cls : 'modal-title',
2240 if(this.specificTitle){
2246 if (this.allow_close) {
2257 style : 'display: none',
2260 cls: "modal-dialog",
2263 cls : "modal-content",
2266 cls : 'modal-header',
2271 cls : 'modal-footer',
2275 cls: 'btn-' + this.buttonPosition
2292 modal.cls += ' fade';
2298 getChildContainer : function() {
2303 getButtonContainer : function() {
2304 return this.el.select('.modal-footer div',true).first();
2307 initEvents : function()
2309 if (this.allow_close) {
2310 this.closeEl.on('click', this.hide, this);
2316 if (!this.rendered) {
2320 this.el.setStyle('display', 'block');
2324 (function(){ _this.el.addClass('in'); }).defer(50);
2326 this.el.addClass('in');
2329 // not sure how we can show data in here..
2331 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2334 Roo.get(document.body).addClass("x-body-masked");
2335 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2337 this.el.setStyle('zIndex', '10001');
2339 this.fireEvent('show', this);
2346 Roo.get(document.body).removeClass("x-body-masked");
2347 this.el.removeClass('in');
2351 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2353 this.el.setStyle('display', 'none');
2356 this.fireEvent('hide', this);
2359 addButton : function(str, cb)
2363 var b = Roo.apply({}, { html : str } );
2364 b.xns = b.xns || Roo.bootstrap;
2365 b.xtype = b.xtype || 'Button';
2366 if (typeof(b.listeners) == 'undefined') {
2367 b.listeners = { click : cb.createDelegate(this) };
2370 var btn = Roo.factory(b);
2372 btn.onRender(this.el.select('.modal-footer div').first());
2378 setDefaultButton : function(btn)
2380 //this.el.select('.modal-footer').()
2382 resizeTo: function(w,h)
2386 setContentSize : function(w, h)
2390 onButtonClick: function(btn,e)
2393 this.fireEvent('btnclick', btn.name, e);
2396 * Set the title of the Dialog
2397 * @param {String} str new Title
2399 setTitle: function(str) {
2400 this.titleEl.dom.innerHTML = str;
2403 * Set the body of the Dialog
2404 * @param {String} str new Title
2406 setBody: function(str) {
2407 this.bodyEl.dom.innerHTML = str;
2410 * Set the body of the Dialog using the template
2411 * @param {Obj} data - apply this data to the template and replace the body contents.
2413 applyBody: function(obj)
2416 Roo.log("Error - using apply Body without a template");
2419 this.tmpl.overwrite(this.bodyEl, obj);
2425 Roo.apply(Roo.bootstrap.Modal, {
2427 * Button config that displays a single OK button
2436 * Button config that displays Yes and No buttons
2452 * Button config that displays OK and Cancel buttons
2467 * Button config that displays Yes, No and Cancel buttons
2490 * messagebox - can be used as a replace
2494 * @class Roo.MessageBox
2495 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2499 Roo.Msg.alert('Status', 'Changes saved successfully.');
2501 // Prompt for user data:
2502 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2504 // process text value...
2508 // Show a dialog using config options:
2510 title:'Save Changes?',
2511 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2512 buttons: Roo.Msg.YESNOCANCEL,
2519 Roo.bootstrap.MessageBox = function(){
2520 var dlg, opt, mask, waitTimer;
2521 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2522 var buttons, activeTextEl, bwidth;
2526 var handleButton = function(button){
2528 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2532 var handleHide = function(){
2534 dlg.el.removeClass(opt.cls);
2537 // Roo.TaskMgr.stop(waitTimer);
2538 // waitTimer = null;
2543 var updateButtons = function(b){
2546 buttons["ok"].hide();
2547 buttons["cancel"].hide();
2548 buttons["yes"].hide();
2549 buttons["no"].hide();
2550 //dlg.footer.dom.style.display = 'none';
2553 dlg.footerEl.dom.style.display = '';
2554 for(var k in buttons){
2555 if(typeof buttons[k] != "function"){
2558 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2559 width += buttons[k].el.getWidth()+15;
2569 var handleEsc = function(d, k, e){
2570 if(opt && opt.closable !== false){
2580 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2581 * @return {Roo.BasicDialog} The BasicDialog element
2583 getDialog : function(){
2585 dlg = new Roo.bootstrap.Modal( {
2588 //constraintoviewport:false,
2590 //collapsible : false,
2595 //buttonAlign:"center",
2596 closeClick : function(){
2597 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2600 handleButton("cancel");
2605 dlg.on("hide", handleHide);
2607 //dlg.addKeyListener(27, handleEsc);
2609 this.buttons = buttons;
2610 var bt = this.buttonText;
2611 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2612 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2613 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2614 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2616 bodyEl = dlg.bodyEl.createChild({
2618 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2619 '<textarea class="roo-mb-textarea"></textarea>' +
2620 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2622 msgEl = bodyEl.dom.firstChild;
2623 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2624 textboxEl.enableDisplayMode();
2625 textboxEl.addKeyListener([10,13], function(){
2626 if(dlg.isVisible() && opt && opt.buttons){
2629 }else if(opt.buttons.yes){
2630 handleButton("yes");
2634 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2635 textareaEl.enableDisplayMode();
2636 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2637 progressEl.enableDisplayMode();
2638 var pf = progressEl.dom.firstChild;
2640 pp = Roo.get(pf.firstChild);
2641 pp.setHeight(pf.offsetHeight);
2649 * Updates the message box body text
2650 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2651 * the XHTML-compliant non-breaking space character '&#160;')
2652 * @return {Roo.MessageBox} This message box
2654 updateText : function(text){
2655 if(!dlg.isVisible() && !opt.width){
2656 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2658 msgEl.innerHTML = text || ' ';
2660 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2661 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2663 Math.min(opt.width || cw , this.maxWidth),
2664 Math.max(opt.minWidth || this.minWidth, bwidth)
2667 activeTextEl.setWidth(w);
2669 if(dlg.isVisible()){
2670 dlg.fixedcenter = false;
2672 // to big, make it scroll. = But as usual stupid IE does not support
2675 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2676 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2677 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2679 bodyEl.dom.style.height = '';
2680 bodyEl.dom.style.overflowY = '';
2683 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2685 bodyEl.dom.style.overflowX = '';
2688 dlg.setContentSize(w, bodyEl.getHeight());
2689 if(dlg.isVisible()){
2690 dlg.fixedcenter = true;
2696 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2697 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2698 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2699 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2700 * @return {Roo.MessageBox} This message box
2702 updateProgress : function(value, text){
2704 this.updateText(text);
2706 if (pp) { // weird bug on my firefox - for some reason this is not defined
2707 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2713 * Returns true if the message box is currently displayed
2714 * @return {Boolean} True if the message box is visible, else false
2716 isVisible : function(){
2717 return dlg && dlg.isVisible();
2721 * Hides the message box if it is displayed
2724 if(this.isVisible()){
2730 * Displays a new message box, or reinitializes an existing message box, based on the config options
2731 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2732 * The following config object properties are supported:
2734 Property Type Description
2735 ---------- --------------- ------------------------------------------------------------------------------------
2736 animEl String/Element An id or Element from which the message box should animate as it opens and
2737 closes (defaults to undefined)
2738 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2739 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2740 closable Boolean False to hide the top-right close button (defaults to true). Note that
2741 progress and wait dialogs will ignore this property and always hide the
2742 close button as they can only be closed programmatically.
2743 cls String A custom CSS class to apply to the message box element
2744 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2745 displayed (defaults to 75)
2746 fn Function A callback function to execute after closing the dialog. The arguments to the
2747 function will be btn (the name of the button that was clicked, if applicable,
2748 e.g. "ok"), and text (the value of the active text field, if applicable).
2749 Progress and wait dialogs will ignore this option since they do not respond to
2750 user actions and can only be closed programmatically, so any required function
2751 should be called by the same code after it closes the dialog.
2752 icon String A CSS class that provides a background image to be used as an icon for
2753 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2754 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2755 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2756 modal Boolean False to allow user interaction with the page while the message box is
2757 displayed (defaults to true)
2758 msg String A string that will replace the existing message box body text (defaults
2759 to the XHTML-compliant non-breaking space character ' ')
2760 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2761 progress Boolean True to display a progress bar (defaults to false)
2762 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2763 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2764 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2765 title String The title text
2766 value String The string value to set into the active textbox element if displayed
2767 wait Boolean True to display a progress bar (defaults to false)
2768 width Number The width of the dialog in pixels
2775 msg: 'Please enter your address:',
2777 buttons: Roo.MessageBox.OKCANCEL,
2780 animEl: 'addAddressBtn'
2783 * @param {Object} config Configuration options
2784 * @return {Roo.MessageBox} This message box
2786 show : function(options)
2789 // this causes nightmares if you show one dialog after another
2790 // especially on callbacks..
2792 if(this.isVisible()){
2795 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2796 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2797 Roo.log("New Dialog Message:" + options.msg )
2798 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2799 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2802 var d = this.getDialog();
2804 d.setTitle(opt.title || " ");
2805 d.closeEl.setDisplayed(opt.closable !== false);
2806 activeTextEl = textboxEl;
2807 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2812 textareaEl.setHeight(typeof opt.multiline == "number" ?
2813 opt.multiline : this.defaultTextHeight);
2814 activeTextEl = textareaEl;
2823 progressEl.setDisplayed(opt.progress === true);
2824 this.updateProgress(0);
2825 activeTextEl.dom.value = opt.value || "";
2827 dlg.setDefaultButton(activeTextEl);
2829 var bs = opt.buttons;
2833 }else if(bs && bs.yes){
2834 db = buttons["yes"];
2836 dlg.setDefaultButton(db);
2838 bwidth = updateButtons(opt.buttons);
2839 this.updateText(opt.msg);
2841 d.el.addClass(opt.cls);
2843 d.proxyDrag = opt.proxyDrag === true;
2844 d.modal = opt.modal !== false;
2845 d.mask = opt.modal !== false ? mask : false;
2847 // force it to the end of the z-index stack so it gets a cursor in FF
2848 document.body.appendChild(dlg.el.dom);
2849 d.animateTarget = null;
2850 d.show(options.animEl);
2856 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2857 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2858 * and closing the message box when the process is complete.
2859 * @param {String} title The title bar text
2860 * @param {String} msg The message box body text
2861 * @return {Roo.MessageBox} This message box
2863 progress : function(title, msg){
2870 minWidth: this.minProgressWidth,
2877 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2878 * If a callback function is passed it will be called after the user clicks the button, and the
2879 * id of the button that was clicked will be passed as the only parameter to the callback
2880 * (could also be the top-right close button).
2881 * @param {String} title The title bar text
2882 * @param {String} msg The message box body text
2883 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2884 * @param {Object} scope (optional) The scope of the callback function
2885 * @return {Roo.MessageBox} This message box
2887 alert : function(title, msg, fn, scope){
2900 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2901 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2902 * You are responsible for closing the message box when the process is complete.
2903 * @param {String} msg The message box body text
2904 * @param {String} title (optional) The title bar text
2905 * @return {Roo.MessageBox} This message box
2907 wait : function(msg, title){
2918 waitTimer = Roo.TaskMgr.start({
2920 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2928 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2929 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2930 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2931 * @param {String} title The title bar text
2932 * @param {String} msg The message box body text
2933 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2934 * @param {Object} scope (optional) The scope of the callback function
2935 * @return {Roo.MessageBox} This message box
2937 confirm : function(title, msg, fn, scope){
2941 buttons: this.YESNO,
2950 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2951 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2952 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2953 * (could also be the top-right close button) and the text that was entered will be passed as the two
2954 * parameters to the callback.
2955 * @param {String} title The title bar text
2956 * @param {String} msg The message box body text
2957 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2958 * @param {Object} scope (optional) The scope of the callback function
2959 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2960 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2961 * @return {Roo.MessageBox} This message box
2963 prompt : function(title, msg, fn, scope, multiline){
2967 buttons: this.OKCANCEL,
2972 multiline: multiline,
2979 * Button config that displays a single OK button
2984 * Button config that displays Yes and No buttons
2987 YESNO : {yes:true, no:true},
2989 * Button config that displays OK and Cancel buttons
2992 OKCANCEL : {ok:true, cancel:true},
2994 * Button config that displays Yes, No and Cancel buttons
2997 YESNOCANCEL : {yes:true, no:true, cancel:true},
3000 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3003 defaultTextHeight : 75,
3005 * The maximum width in pixels of the message box (defaults to 600)
3010 * The minimum width in pixels of the message box (defaults to 100)
3015 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3016 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3019 minProgressWidth : 250,
3021 * An object containing the default button text strings that can be overriden for localized language support.
3022 * Supported properties are: ok, cancel, yes and no.
3023 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3036 * Shorthand for {@link Roo.MessageBox}
3038 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3039 Roo.Msg = Roo.Msg || Roo.MessageBox;
3048 * @class Roo.bootstrap.Navbar
3049 * @extends Roo.bootstrap.Component
3050 * Bootstrap Navbar class
3053 * Create a new Navbar
3054 * @param {Object} config The config object
3058 Roo.bootstrap.Navbar = function(config){
3059 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3063 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3072 getAutoCreate : function(){
3075 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3079 initEvents :function ()
3081 //Roo.log(this.el.select('.navbar-toggle',true));
3082 this.el.select('.navbar-toggle',true).on('click', function() {
3083 // Roo.log('click');
3084 this.el.select('.navbar-collapse',true).toggleClass('in');
3092 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3094 var size = this.el.getSize();
3095 this.maskEl.setSize(size.width, size.height);
3096 this.maskEl.enableDisplayMode("block");
3105 getChildContainer : function()
3107 if (this.el.select('.collapse').getCount()) {
3108 return this.el.select('.collapse',true).first();
3141 * @class Roo.bootstrap.NavSimplebar
3142 * @extends Roo.bootstrap.Navbar
3143 * Bootstrap Sidebar class
3145 * @cfg {Boolean} inverse is inverted color
3147 * @cfg {String} type (nav | pills | tabs)
3148 * @cfg {Boolean} arrangement stacked | justified
3149 * @cfg {String} align (left | right) alignment
3151 * @cfg {Boolean} main (true|false) main nav bar? default false
3152 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3154 * @cfg {String} tag (header|footer|nav|div) default is nav
3160 * Create a new Sidebar
3161 * @param {Object} config The config object
3165 Roo.bootstrap.NavSimplebar = function(config){
3166 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3169 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3185 getAutoCreate : function(){
3189 tag : this.tag || 'div',
3202 this.type = this.type || 'nav';
3203 if (['tabs','pills'].indexOf(this.type)!==-1) {
3204 cfg.cn[0].cls += ' nav-' + this.type
3208 if (this.type!=='nav') {
3209 Roo.log('nav type must be nav/tabs/pills')
3211 cfg.cn[0].cls += ' navbar-nav'
3217 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3218 cfg.cn[0].cls += ' nav-' + this.arrangement;
3222 if (this.align === 'right') {
3223 cfg.cn[0].cls += ' navbar-right';
3227 cfg.cls += ' navbar-inverse';
3254 * @class Roo.bootstrap.NavHeaderbar
3255 * @extends Roo.bootstrap.NavSimplebar
3256 * Bootstrap Sidebar class
3258 * @cfg {String} brand what is brand
3259 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3260 * @cfg {String} brand_href href of the brand
3261 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3262 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3263 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3264 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3267 * Create a new Sidebar
3268 * @param {Object} config The config object
3272 Roo.bootstrap.NavHeaderbar = function(config){
3273 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3277 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3284 desktopCenter : false,
3287 getAutoCreate : function(){
3290 tag: this.nav || 'nav',
3297 if (this.desktopCenter) {
3298 cn.push({cls : 'container', cn : []});
3305 cls: 'navbar-header',
3310 cls: 'navbar-toggle',
3311 'data-toggle': 'collapse',
3316 html: 'Toggle navigation'
3338 cls: 'collapse navbar-collapse',
3342 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3344 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3345 cfg.cls += ' navbar-' + this.position;
3347 // tag can override this..
3349 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3352 if (this.brand !== '') {
3355 href: this.brand_href ? this.brand_href : '#',
3356 cls: 'navbar-brand',
3364 cfg.cls += ' main-nav';
3372 getHeaderChildContainer : function()
3374 if (this.el.select('.navbar-header').getCount()) {
3375 return this.el.select('.navbar-header',true).first();
3378 return this.getChildContainer();
3382 initEvents : function()
3384 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3386 if (this.autohide) {
3391 Roo.get(document).on('scroll',function(e) {
3392 var ns = Roo.get(document).getScroll().top;
3393 var os = prevScroll;
3397 ft.removeClass('slideDown');
3398 ft.addClass('slideUp');
3401 ft.removeClass('slideUp');
3402 ft.addClass('slideDown');
3426 * @class Roo.bootstrap.NavSidebar
3427 * @extends Roo.bootstrap.Navbar
3428 * Bootstrap Sidebar class
3431 * Create a new Sidebar
3432 * @param {Object} config The config object
3436 Roo.bootstrap.NavSidebar = function(config){
3437 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3440 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3442 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3444 getAutoCreate : function(){
3449 cls: 'sidebar sidebar-nav'
3471 * @class Roo.bootstrap.NavGroup
3472 * @extends Roo.bootstrap.Component
3473 * Bootstrap NavGroup class
3474 * @cfg {String} align left | right
3475 * @cfg {Boolean} inverse false | true
3476 * @cfg {String} type (nav|pills|tab) default nav
3477 * @cfg {String} navId - reference Id for navbar.
3481 * Create a new nav group
3482 * @param {Object} config The config object
3485 Roo.bootstrap.NavGroup = function(config){
3486 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3489 Roo.bootstrap.NavGroup.register(this);
3493 * Fires when the active item changes
3494 * @param {Roo.bootstrap.NavGroup} this
3495 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3496 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3503 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3514 getAutoCreate : function()
3516 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3523 if (['tabs','pills'].indexOf(this.type)!==-1) {
3524 cfg.cls += ' nav-' + this.type
3526 if (this.type!=='nav') {
3527 Roo.log('nav type must be nav/tabs/pills')
3529 cfg.cls += ' navbar-nav'
3532 if (this.parent().sidebar) {
3535 cls: 'dashboard-menu sidebar-menu'
3541 if (this.form === true) {
3547 if (this.align === 'right') {
3548 cfg.cls += ' navbar-right';
3550 cfg.cls += ' navbar-left';
3554 if (this.align === 'right') {
3555 cfg.cls += ' navbar-right';
3559 cfg.cls += ' navbar-inverse';
3567 * sets the active Navigation item
3568 * @param {Roo.bootstrap.NavItem} the new current navitem
3570 setActiveItem : function(item)
3573 Roo.each(this.navItems, function(v){
3578 v.setActive(false, true);
3585 item.setActive(true, true);
3586 this.fireEvent('changed', this, item, prev);
3591 * gets the active Navigation item
3592 * @return {Roo.bootstrap.NavItem} the current navitem
3594 getActive : function()
3598 Roo.each(this.navItems, function(v){
3609 indexOfNav : function()
3613 Roo.each(this.navItems, function(v,i){
3624 * adds a Navigation item
3625 * @param {Roo.bootstrap.NavItem} the navitem to add
3627 addItem : function(cfg)
3629 var cn = new Roo.bootstrap.NavItem(cfg);
3631 cn.parentId = this.id;
3632 cn.onRender(this.el, null);
3636 * register a Navigation item
3637 * @param {Roo.bootstrap.NavItem} the navitem to add
3639 register : function(item)
3641 this.navItems.push( item);
3642 item.navId = this.navId;
3647 * clear all the Navigation item
3650 clearAll : function()
3653 this.el.dom.innerHTML = '';
3656 getNavItem: function(tabId)
3659 Roo.each(this.navItems, function(e) {
3660 if (e.tabId == tabId) {
3670 setActiveNext : function()
3672 var i = this.indexOfNav(this.getActive());
3673 if (i > this.navItems.length) {
3676 this.setActiveItem(this.navItems[i+1]);
3678 setActivePrev : function()
3680 var i = this.indexOfNav(this.getActive());
3684 this.setActiveItem(this.navItems[i-1]);
3686 clearWasActive : function(except) {
3687 Roo.each(this.navItems, function(e) {
3688 if (e.tabId != except.tabId && e.was_active) {
3689 e.was_active = false;
3696 getWasActive : function ()
3699 Roo.each(this.navItems, function(e) {
3714 Roo.apply(Roo.bootstrap.NavGroup, {
3718 * register a Navigation Group
3719 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3721 register : function(navgrp)
3723 this.groups[navgrp.navId] = navgrp;
3727 * fetch a Navigation Group based on the navigation ID
3728 * @param {string} the navgroup to add
3729 * @returns {Roo.bootstrap.NavGroup} the navgroup
3731 get: function(navId) {
3732 if (typeof(this.groups[navId]) == 'undefined') {
3734 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3736 return this.groups[navId] ;
3751 * @class Roo.bootstrap.NavItem
3752 * @extends Roo.bootstrap.Component
3753 * Bootstrap Navbar.NavItem class
3754 * @cfg {String} href link to
3755 * @cfg {String} html content of button
3756 * @cfg {String} badge text inside badge
3757 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3758 * @cfg {String} glyphicon name of glyphicon
3759 * @cfg {String} icon name of font awesome icon
3760 * @cfg {Boolean} active Is item active
3761 * @cfg {Boolean} disabled Is item disabled
3763 * @cfg {Boolean} preventDefault (true | false) default false
3764 * @cfg {String} tabId the tab that this item activates.
3765 * @cfg {String} tagtype (a|span) render as a href or span?
3766 * @cfg {Boolean} animateRef (true|false) link to element default false
3769 * Create a new Navbar Item
3770 * @param {Object} config The config object
3772 Roo.bootstrap.NavItem = function(config){
3773 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3778 * The raw click event for the entire grid.
3779 * @param {Roo.EventObject} e
3784 * Fires when the active item active state changes
3785 * @param {Roo.bootstrap.NavItem} this
3786 * @param {boolean} state the new state
3792 * Fires when scroll to element
3793 * @param {Roo.bootstrap.NavItem} this
3794 * @param {Object} options
3795 * @param {Roo.EventObject} e
3803 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3811 preventDefault : false,
3818 getAutoCreate : function(){
3826 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3828 if (this.disabled) {
3829 cfg.cls += ' disabled';
3832 if (this.href || this.html || this.glyphicon || this.icon) {
3836 href : this.href || "#",
3837 html: this.html || ''
3842 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3845 if(this.glyphicon) {
3846 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3851 cfg.cn[0].html += " <span class='caret'></span>";
3855 if (this.badge !== '') {
3857 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3865 initEvents: function()
3867 if (typeof (this.menu) != 'undefined') {
3868 this.menu.parentType = this.xtype;
3869 this.menu.triggerEl = this.el;
3870 this.menu = this.addxtype(Roo.apply({}, this.menu));
3873 this.el.select('a',true).on('click', this.onClick, this);
3875 if(this.tagtype == 'span'){
3876 this.el.select('span',true).on('click', this.onClick, this);
3879 // at this point parent should be available..
3880 this.parent().register(this);
3883 onClick : function(e)
3886 this.preventDefault ||
3888 (this.animateRef && this.href.charAt(0) == '#')
3893 if (this.disabled) {
3897 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3898 if (tg && tg.transition) {
3899 Roo.log("waiting for the transitionend");
3903 Roo.log("fire event clicked");
3904 if(this.fireEvent('click', this, e) === false){
3908 if(this.tagtype == 'span'){
3912 if(this.animateRef && this.href.charAt(0) == '#'){
3913 this.scrollToElement(e);
3917 var p = this.parent();
3918 if (['tabs','pills'].indexOf(p.type)!==-1) {
3919 if (typeof(p.setActiveItem) !== 'undefined') {
3920 p.setActiveItem(this);
3923 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3924 if (p.parentType == 'NavHeaderbar' && !this.menu) {
3925 // remove the collapsed menu expand...
3926 p.parent().el.select('.navbar-collapse',true).removeClass('in');
3931 isActive: function () {
3934 setActive : function(state, fire, is_was_active)
3936 if (this.active && !state & this.navId) {
3937 this.was_active = true;
3938 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3940 nv.clearWasActive(this);
3944 this.active = state;
3947 this.el.removeClass('active');
3948 } else if (!this.el.hasClass('active')) {
3949 this.el.addClass('active');
3952 this.fireEvent('changed', this, state);
3955 // show a panel if it's registered and related..
3957 if (!this.navId || !this.tabId || !state || is_was_active) {
3961 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3965 var pan = tg.getPanelByName(this.tabId);
3969 // if we can not flip to new panel - go back to old nav highlight..
3970 if (false == tg.showPanel(pan)) {
3971 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3973 var onav = nv.getWasActive();
3975 onav.setActive(true, false, true);
3984 // this should not be here...
3985 setDisabled : function(state)
3987 this.disabled = state;
3989 this.el.removeClass('disabled');
3990 } else if (!this.el.hasClass('disabled')) {
3991 this.el.addClass('disabled');
3997 * Fetch the element to display the tooltip on.
3998 * @return {Roo.Element} defaults to this.el
4000 tooltipEl : function()
4002 return this.el.select('' + this.tagtype + '', true).first();
4005 scrollToElement : function(e)
4007 var c = document.body;
4009 var target = Roo.get(c).select('a[name=' + this.href.replace('#', '') +']', true).first();
4015 var o = target.calcOffsetsTo(c);
4022 this.fireEvent('scrollto', this, options, e);
4024 Roo.get(c).scrollTo('top', options.value, true);
4037 * <span> icon </span>
4038 * <span> text </span>
4039 * <span>badge </span>
4043 * @class Roo.bootstrap.NavSidebarItem
4044 * @extends Roo.bootstrap.NavItem
4045 * Bootstrap Navbar.NavSidebarItem class
4047 * Create a new Navbar Button
4048 * @param {Object} config The config object
4050 Roo.bootstrap.NavSidebarItem = function(config){
4051 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4056 * The raw click event for the entire grid.
4057 * @param {Roo.EventObject} e
4062 * Fires when the active item active state changes
4063 * @param {Roo.bootstrap.NavSidebarItem} this
4064 * @param {boolean} state the new state
4072 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4075 getAutoCreate : function(){
4080 href : this.href || '#',
4092 html : this.html || ''
4097 cfg.cls += ' active';
4101 if (this.glyphicon || this.icon) {
4102 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4103 a.cn.push({ tag : 'i', cls : c }) ;
4108 if (this.badge !== '') {
4109 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4113 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4114 a.cls += 'dropdown-toggle treeview' ;
4138 * @class Roo.bootstrap.Row
4139 * @extends Roo.bootstrap.Component
4140 * Bootstrap Row class (contains columns...)
4144 * @param {Object} config The config object
4147 Roo.bootstrap.Row = function(config){
4148 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4151 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4153 getAutoCreate : function(){
4172 * @class Roo.bootstrap.Element
4173 * @extends Roo.bootstrap.Component
4174 * Bootstrap Element class
4175 * @cfg {String} html contents of the element
4176 * @cfg {String} tag tag of the element
4177 * @cfg {String} cls class of the element
4180 * Create a new Element
4181 * @param {Object} config The config object
4184 Roo.bootstrap.Element = function(config){
4185 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4188 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4195 getAutoCreate : function(){
4220 * @class Roo.bootstrap.Pagination
4221 * @extends Roo.bootstrap.Component
4222 * Bootstrap Pagination class
4223 * @cfg {String} size xs | sm | md | lg
4224 * @cfg {Boolean} inverse false | true
4227 * Create a new Pagination
4228 * @param {Object} config The config object
4231 Roo.bootstrap.Pagination = function(config){
4232 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4235 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4241 getAutoCreate : function(){
4247 cfg.cls += ' inverse';
4253 cfg.cls += " " + this.cls;
4271 * @class Roo.bootstrap.PaginationItem
4272 * @extends Roo.bootstrap.Component
4273 * Bootstrap PaginationItem class
4274 * @cfg {String} html text
4275 * @cfg {String} href the link
4276 * @cfg {Boolean} preventDefault (true | false) default true
4277 * @cfg {Boolean} active (true | false) default false
4278 * @cfg {Boolean} disabled default false
4282 * Create a new PaginationItem
4283 * @param {Object} config The config object
4287 Roo.bootstrap.PaginationItem = function(config){
4288 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4293 * The raw click event for the entire grid.
4294 * @param {Roo.EventObject} e
4300 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4304 preventDefault: true,
4309 getAutoCreate : function(){
4315 href : this.href ? this.href : '#',
4316 html : this.html ? this.html : ''
4326 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4330 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4336 initEvents: function() {
4338 this.el.on('click', this.onClick, this);
4341 onClick : function(e)
4343 Roo.log('PaginationItem on click ');
4344 if(this.preventDefault){
4352 this.fireEvent('click', this, e);
4368 * @class Roo.bootstrap.Slider
4369 * @extends Roo.bootstrap.Component
4370 * Bootstrap Slider class
4373 * Create a new Slider
4374 * @param {Object} config The config object
4377 Roo.bootstrap.Slider = function(config){
4378 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4381 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4383 getAutoCreate : function(){
4387 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4391 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4403 * Ext JS Library 1.1.1
4404 * Copyright(c) 2006-2007, Ext JS, LLC.
4406 * Originally Released Under LGPL - original licence link has changed is not relivant.
4409 * <script type="text/javascript">
4414 * @class Roo.grid.ColumnModel
4415 * @extends Roo.util.Observable
4416 * This is the default implementation of a ColumnModel used by the Grid. It defines
4417 * the columns in the grid.
4420 var colModel = new Roo.grid.ColumnModel([
4421 {header: "Ticker", width: 60, sortable: true, locked: true},
4422 {header: "Company Name", width: 150, sortable: true},
4423 {header: "Market Cap.", width: 100, sortable: true},
4424 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4425 {header: "Employees", width: 100, sortable: true, resizable: false}
4430 * The config options listed for this class are options which may appear in each
4431 * individual column definition.
4432 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4434 * @param {Object} config An Array of column config objects. See this class's
4435 * config objects for details.
4437 Roo.grid.ColumnModel = function(config){
4439 * The config passed into the constructor
4441 this.config = config;
4444 // if no id, create one
4445 // if the column does not have a dataIndex mapping,
4446 // map it to the order it is in the config
4447 for(var i = 0, len = config.length; i < len; i++){
4449 if(typeof c.dataIndex == "undefined"){
4452 if(typeof c.renderer == "string"){
4453 c.renderer = Roo.util.Format[c.renderer];
4455 if(typeof c.id == "undefined"){
4458 if(c.editor && c.editor.xtype){
4459 c.editor = Roo.factory(c.editor, Roo.grid);
4461 if(c.editor && c.editor.isFormField){
4462 c.editor = new Roo.grid.GridEditor(c.editor);
4464 this.lookup[c.id] = c;
4468 * The width of columns which have no width specified (defaults to 100)
4471 this.defaultWidth = 100;
4474 * Default sortable of columns which have no sortable specified (defaults to false)
4477 this.defaultSortable = false;
4481 * @event widthchange
4482 * Fires when the width of a column changes.
4483 * @param {ColumnModel} this
4484 * @param {Number} columnIndex The column index
4485 * @param {Number} newWidth The new width
4487 "widthchange": true,
4489 * @event headerchange
4490 * Fires when the text of a header changes.
4491 * @param {ColumnModel} this
4492 * @param {Number} columnIndex The column index
4493 * @param {Number} newText The new header text
4495 "headerchange": true,
4497 * @event hiddenchange
4498 * Fires when a column is hidden or "unhidden".
4499 * @param {ColumnModel} this
4500 * @param {Number} columnIndex The column index
4501 * @param {Boolean} hidden true if hidden, false otherwise
4503 "hiddenchange": true,
4505 * @event columnmoved
4506 * Fires when a column is moved.
4507 * @param {ColumnModel} this
4508 * @param {Number} oldIndex
4509 * @param {Number} newIndex
4511 "columnmoved" : true,
4513 * @event columlockchange
4514 * Fires when a column's locked state is changed
4515 * @param {ColumnModel} this
4516 * @param {Number} colIndex
4517 * @param {Boolean} locked true if locked
4519 "columnlockchange" : true
4521 Roo.grid.ColumnModel.superclass.constructor.call(this);
4523 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4525 * @cfg {String} header The header text to display in the Grid view.
4528 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4529 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4530 * specified, the column's index is used as an index into the Record's data Array.
4533 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4534 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4537 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4538 * Defaults to the value of the {@link #defaultSortable} property.
4539 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4542 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4545 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4548 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4551 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4554 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4555 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4556 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4557 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4560 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4563 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4566 * @cfg {String} cursor (Optional)
4569 * @cfg {String} tooltip (Optional)
4572 * Returns the id of the column at the specified index.
4573 * @param {Number} index The column index
4574 * @return {String} the id
4576 getColumnId : function(index){
4577 return this.config[index].id;
4581 * Returns the column for a specified id.
4582 * @param {String} id The column id
4583 * @return {Object} the column
4585 getColumnById : function(id){
4586 return this.lookup[id];
4591 * Returns the column for a specified dataIndex.
4592 * @param {String} dataIndex The column dataIndex
4593 * @return {Object|Boolean} the column or false if not found
4595 getColumnByDataIndex: function(dataIndex){
4596 var index = this.findColumnIndex(dataIndex);
4597 return index > -1 ? this.config[index] : false;
4601 * Returns the index for a specified column id.
4602 * @param {String} id The column id
4603 * @return {Number} the index, or -1 if not found
4605 getIndexById : function(id){
4606 for(var i = 0, len = this.config.length; i < len; i++){
4607 if(this.config[i].id == id){
4615 * Returns the index for a specified column dataIndex.
4616 * @param {String} dataIndex The column dataIndex
4617 * @return {Number} the index, or -1 if not found
4620 findColumnIndex : function(dataIndex){
4621 for(var i = 0, len = this.config.length; i < len; i++){
4622 if(this.config[i].dataIndex == dataIndex){
4630 moveColumn : function(oldIndex, newIndex){
4631 var c = this.config[oldIndex];
4632 this.config.splice(oldIndex, 1);
4633 this.config.splice(newIndex, 0, c);
4634 this.dataMap = null;
4635 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4638 isLocked : function(colIndex){
4639 return this.config[colIndex].locked === true;
4642 setLocked : function(colIndex, value, suppressEvent){
4643 if(this.isLocked(colIndex) == value){
4646 this.config[colIndex].locked = value;
4648 this.fireEvent("columnlockchange", this, colIndex, value);
4652 getTotalLockedWidth : function(){
4654 for(var i = 0; i < this.config.length; i++){
4655 if(this.isLocked(i) && !this.isHidden(i)){
4656 this.totalWidth += this.getColumnWidth(i);
4662 getLockedCount : function(){
4663 for(var i = 0, len = this.config.length; i < len; i++){
4664 if(!this.isLocked(i)){
4671 * Returns the number of columns.
4674 getColumnCount : function(visibleOnly){
4675 if(visibleOnly === true){
4677 for(var i = 0, len = this.config.length; i < len; i++){
4678 if(!this.isHidden(i)){
4684 return this.config.length;
4688 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4689 * @param {Function} fn
4690 * @param {Object} scope (optional)
4691 * @return {Array} result
4693 getColumnsBy : function(fn, scope){
4695 for(var i = 0, len = this.config.length; i < len; i++){
4696 var c = this.config[i];
4697 if(fn.call(scope||this, c, i) === true){
4705 * Returns true if the specified column is sortable.
4706 * @param {Number} col The column index
4709 isSortable : function(col){
4710 if(typeof this.config[col].sortable == "undefined"){
4711 return this.defaultSortable;
4713 return this.config[col].sortable;
4717 * Returns the rendering (formatting) function defined for the column.
4718 * @param {Number} col The column index.
4719 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4721 getRenderer : function(col){
4722 if(!this.config[col].renderer){
4723 return Roo.grid.ColumnModel.defaultRenderer;
4725 return this.config[col].renderer;
4729 * Sets the rendering (formatting) function for a column.
4730 * @param {Number} col The column index
4731 * @param {Function} fn The function to use to process the cell's raw data
4732 * to return HTML markup for the grid view. The render function is called with
4733 * the following parameters:<ul>
4734 * <li>Data value.</li>
4735 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4736 * <li>css A CSS style string to apply to the table cell.</li>
4737 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4738 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4739 * <li>Row index</li>
4740 * <li>Column index</li>
4741 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4743 setRenderer : function(col, fn){
4744 this.config[col].renderer = fn;
4748 * Returns the width for the specified column.
4749 * @param {Number} col The column index
4752 getColumnWidth : function(col){
4753 return this.config[col].width * 1 || this.defaultWidth;
4757 * Sets the width for a column.
4758 * @param {Number} col The column index
4759 * @param {Number} width The new width
4761 setColumnWidth : function(col, width, suppressEvent){
4762 this.config[col].width = width;
4763 this.totalWidth = null;
4765 this.fireEvent("widthchange", this, col, width);
4770 * Returns the total width of all columns.
4771 * @param {Boolean} includeHidden True to include hidden column widths
4774 getTotalWidth : function(includeHidden){
4775 if(!this.totalWidth){
4776 this.totalWidth = 0;
4777 for(var i = 0, len = this.config.length; i < len; i++){
4778 if(includeHidden || !this.isHidden(i)){
4779 this.totalWidth += this.getColumnWidth(i);
4783 return this.totalWidth;
4787 * Returns the header for the specified column.
4788 * @param {Number} col The column index
4791 getColumnHeader : function(col){
4792 return this.config[col].header;
4796 * Sets the header for a column.
4797 * @param {Number} col The column index
4798 * @param {String} header The new header
4800 setColumnHeader : function(col, header){
4801 this.config[col].header = header;
4802 this.fireEvent("headerchange", this, col, header);
4806 * Returns the tooltip for the specified column.
4807 * @param {Number} col The column index
4810 getColumnTooltip : function(col){
4811 return this.config[col].tooltip;
4814 * Sets the tooltip for a column.
4815 * @param {Number} col The column index
4816 * @param {String} tooltip The new tooltip
4818 setColumnTooltip : function(col, tooltip){
4819 this.config[col].tooltip = tooltip;
4823 * Returns the dataIndex for the specified column.
4824 * @param {Number} col The column index
4827 getDataIndex : function(col){
4828 return this.config[col].dataIndex;
4832 * Sets the dataIndex for a column.
4833 * @param {Number} col The column index
4834 * @param {Number} dataIndex The new dataIndex
4836 setDataIndex : function(col, dataIndex){
4837 this.config[col].dataIndex = dataIndex;
4843 * Returns true if the cell is editable.
4844 * @param {Number} colIndex The column index
4845 * @param {Number} rowIndex The row index
4848 isCellEditable : function(colIndex, rowIndex){
4849 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4853 * Returns the editor defined for the cell/column.
4854 * return false or null to disable editing.
4855 * @param {Number} colIndex The column index
4856 * @param {Number} rowIndex The row index
4859 getCellEditor : function(colIndex, rowIndex){
4860 return this.config[colIndex].editor;
4864 * Sets if a column is editable.
4865 * @param {Number} col The column index
4866 * @param {Boolean} editable True if the column is editable
4868 setEditable : function(col, editable){
4869 this.config[col].editable = editable;
4874 * Returns true if the column is hidden.
4875 * @param {Number} colIndex The column index
4878 isHidden : function(colIndex){
4879 return this.config[colIndex].hidden;
4884 * Returns true if the column width cannot be changed
4886 isFixed : function(colIndex){
4887 return this.config[colIndex].fixed;
4891 * Returns true if the column can be resized
4894 isResizable : function(colIndex){
4895 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4898 * Sets if a column is hidden.
4899 * @param {Number} colIndex The column index
4900 * @param {Boolean} hidden True if the column is hidden
4902 setHidden : function(colIndex, hidden){
4903 this.config[colIndex].hidden = hidden;
4904 this.totalWidth = null;
4905 this.fireEvent("hiddenchange", this, colIndex, hidden);
4909 * Sets the editor for a column.
4910 * @param {Number} col The column index
4911 * @param {Object} editor The editor object
4913 setEditor : function(col, editor){
4914 this.config[col].editor = editor;
4918 Roo.grid.ColumnModel.defaultRenderer = function(value){
4919 if(typeof value == "string" && value.length < 1){
4925 // Alias for backwards compatibility
4926 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4929 * Ext JS Library 1.1.1
4930 * Copyright(c) 2006-2007, Ext JS, LLC.
4932 * Originally Released Under LGPL - original licence link has changed is not relivant.
4935 * <script type="text/javascript">
4939 * @class Roo.LoadMask
4940 * A simple utility class for generically masking elements while loading data. If the element being masked has
4941 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4942 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4943 * element's UpdateManager load indicator and will be destroyed after the initial load.
4945 * Create a new LoadMask
4946 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4947 * @param {Object} config The config object
4949 Roo.LoadMask = function(el, config){
4950 this.el = Roo.get(el);
4951 Roo.apply(this, config);
4953 this.store.on('beforeload', this.onBeforeLoad, this);
4954 this.store.on('load', this.onLoad, this);
4955 this.store.on('loadexception', this.onLoadException, this);
4956 this.removeMask = false;
4958 var um = this.el.getUpdateManager();
4959 um.showLoadIndicator = false; // disable the default indicator
4960 um.on('beforeupdate', this.onBeforeLoad, this);
4961 um.on('update', this.onLoad, this);
4962 um.on('failure', this.onLoad, this);
4963 this.removeMask = true;
4967 Roo.LoadMask.prototype = {
4969 * @cfg {Boolean} removeMask
4970 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4971 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4975 * The text to display in a centered loading message box (defaults to 'Loading...')
4979 * @cfg {String} msgCls
4980 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4982 msgCls : 'x-mask-loading',
4985 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4991 * Disables the mask to prevent it from being displayed
4993 disable : function(){
4994 this.disabled = true;
4998 * Enables the mask so that it can be displayed
5000 enable : function(){
5001 this.disabled = false;
5004 onLoadException : function()
5008 if (typeof(arguments[3]) != 'undefined') {
5009 Roo.MessageBox.alert("Error loading",arguments[3]);
5013 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5014 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5023 this.el.unmask(this.removeMask);
5028 this.el.unmask(this.removeMask);
5032 onBeforeLoad : function(){
5034 this.el.mask(this.msg, this.msgCls);
5039 destroy : function(){
5041 this.store.un('beforeload', this.onBeforeLoad, this);
5042 this.store.un('load', this.onLoad, this);
5043 this.store.un('loadexception', this.onLoadException, this);
5045 var um = this.el.getUpdateManager();
5046 um.un('beforeupdate', this.onBeforeLoad, this);
5047 um.un('update', this.onLoad, this);
5048 um.un('failure', this.onLoad, this);
5059 * @class Roo.bootstrap.Table
5060 * @extends Roo.bootstrap.Component
5061 * Bootstrap Table class
5062 * @cfg {String} cls table class
5063 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5064 * @cfg {String} bgcolor Specifies the background color for a table
5065 * @cfg {Number} border Specifies whether the table cells should have borders or not
5066 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5067 * @cfg {Number} cellspacing Specifies the space between cells
5068 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5069 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5070 * @cfg {String} sortable Specifies that the table should be sortable
5071 * @cfg {String} summary Specifies a summary of the content of a table
5072 * @cfg {Number} width Specifies the width of a table
5073 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5075 * @cfg {boolean} striped Should the rows be alternative striped
5076 * @cfg {boolean} bordered Add borders to the table
5077 * @cfg {boolean} hover Add hover highlighting
5078 * @cfg {boolean} condensed Format condensed
5079 * @cfg {boolean} responsive Format condensed
5080 * @cfg {Boolean} loadMask (true|false) default false
5081 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5082 * @cfg {Boolean} thead (true|false) generate thead, default true
5083 * @cfg {Boolean} RowSelection (true|false) default false
5084 * @cfg {Boolean} CellSelection (true|false) default false
5085 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5089 * Create a new Table
5090 * @param {Object} config The config object
5093 Roo.bootstrap.Table = function(config){
5094 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5097 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5098 this.sm = this.selModel;
5099 this.sm.xmodule = this.xmodule || false;
5101 if (this.cm && typeof(this.cm.config) == 'undefined') {
5102 this.colModel = new Roo.grid.ColumnModel(this.cm);
5103 this.cm = this.colModel;
5104 this.cm.xmodule = this.xmodule || false;
5107 this.store= Roo.factory(this.store, Roo.data);
5108 this.ds = this.store;
5109 this.ds.xmodule = this.xmodule || false;
5112 if (this.footer && this.store) {
5113 this.footer.dataSource = this.ds;
5114 this.footer = Roo.factory(this.footer);
5121 * Fires when a cell is clicked
5122 * @param {Roo.bootstrap.Table} this
5123 * @param {Roo.Element} el
5124 * @param {Number} rowIndex
5125 * @param {Number} columnIndex
5126 * @param {Roo.EventObject} e
5130 * @event celldblclick
5131 * Fires when a cell is double clicked
5132 * @param {Roo.bootstrap.Table} this
5133 * @param {Roo.Element} el
5134 * @param {Number} rowIndex
5135 * @param {Number} columnIndex
5136 * @param {Roo.EventObject} e
5138 "celldblclick" : true,
5141 * Fires when a row is clicked
5142 * @param {Roo.bootstrap.Table} this
5143 * @param {Roo.Element} el
5144 * @param {Number} rowIndex
5145 * @param {Roo.EventObject} e
5149 * @event rowdblclick
5150 * Fires when a row is double clicked
5151 * @param {Roo.bootstrap.Table} this
5152 * @param {Roo.Element} el
5153 * @param {Number} rowIndex
5154 * @param {Roo.EventObject} e
5156 "rowdblclick" : true,
5159 * Fires when a mouseover occur
5160 * @param {Roo.bootstrap.Table} this
5161 * @param {Roo.Element} el
5162 * @param {Number} rowIndex
5163 * @param {Number} columnIndex
5164 * @param {Roo.EventObject} e
5169 * Fires when a mouseout occur
5170 * @param {Roo.bootstrap.Table} this
5171 * @param {Roo.Element} el
5172 * @param {Number} rowIndex
5173 * @param {Number} columnIndex
5174 * @param {Roo.EventObject} e
5179 * Fires when a row is rendered, so you can change add a style to it.
5180 * @param {Roo.bootstrap.Table} this
5181 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5185 * @event rowsrendered
5186 * Fires when all the rows have been rendered
5187 * @param {Roo.bootstrap.Table} this
5189 'rowsrendered' : true
5194 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5218 RowSelection : false,
5219 CellSelection : false,
5222 // Roo.Element - the tbody
5225 getAutoCreate : function(){
5226 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5235 cfg.cls += ' table-striped';
5239 cfg.cls += ' table-hover';
5241 if (this.bordered) {
5242 cfg.cls += ' table-bordered';
5244 if (this.condensed) {
5245 cfg.cls += ' table-condensed';
5247 if (this.responsive) {
5248 cfg.cls += ' table-responsive';
5252 cfg.cls+= ' ' +this.cls;
5255 // this lot should be simplifed...
5258 cfg.align=this.align;
5261 cfg.bgcolor=this.bgcolor;
5264 cfg.border=this.border;
5266 if (this.cellpadding) {
5267 cfg.cellpadding=this.cellpadding;
5269 if (this.cellspacing) {
5270 cfg.cellspacing=this.cellspacing;
5273 cfg.frame=this.frame;
5276 cfg.rules=this.rules;
5278 if (this.sortable) {
5279 cfg.sortable=this.sortable;
5282 cfg.summary=this.summary;
5285 cfg.width=this.width;
5288 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5291 if(this.store || this.cm){
5293 cfg.cn.push(this.renderHeader());
5296 cfg.cn.push(this.renderBody());
5299 cfg.cn.push(this.renderFooter());
5302 cfg.cls+= ' TableGrid';
5305 return { cn : [ cfg ] };
5308 initEvents : function()
5310 if(!this.store || !this.cm){
5314 //Roo.log('initEvents with ds!!!!');
5316 this.mainBody = this.el.select('tbody', true).first();
5321 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5322 e.on('click', _this.sort, _this);
5325 this.el.on("click", this.onClick, this);
5326 this.el.on("dblclick", this.onDblClick, this);
5328 // why is this done????? = it breaks dialogs??
5329 //this.parent().el.setStyle('position', 'relative');
5333 this.footer.parentId = this.id;
5334 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5337 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5339 this.store.on('load', this.onLoad, this);
5340 this.store.on('beforeload', this.onBeforeLoad, this);
5341 this.store.on('update', this.onUpdate, this);
5342 this.store.on('add', this.onAdd, this);
5346 onMouseover : function(e, el)
5348 var cell = Roo.get(el);
5354 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5355 cell = cell.findParent('td', false, true);
5358 var row = cell.findParent('tr', false, true);
5359 var cellIndex = cell.dom.cellIndex;
5360 var rowIndex = row.dom.rowIndex - 1; // start from 0
5362 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5366 onMouseout : function(e, el)
5368 var cell = Roo.get(el);
5374 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5375 cell = cell.findParent('td', false, true);
5378 var row = cell.findParent('tr', false, true);
5379 var cellIndex = cell.dom.cellIndex;
5380 var rowIndex = row.dom.rowIndex - 1; // start from 0
5382 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5386 onClick : function(e, el)
5388 var cell = Roo.get(el);
5390 if(!cell || (!this.CellSelection && !this.RowSelection)){
5394 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5395 cell = cell.findParent('td', false, true);
5398 if(!cell || typeof(cell) == 'undefined'){
5402 var row = cell.findParent('tr', false, true);
5404 if(!row || typeof(row) == 'undefined'){
5408 var cellIndex = cell.dom.cellIndex;
5409 var rowIndex = this.getRowIndex(row);
5411 if(this.CellSelection){
5412 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5415 if(this.RowSelection){
5416 this.fireEvent('rowclick', this, row, rowIndex, e);
5422 onDblClick : function(e,el)
5424 var cell = Roo.get(el);
5426 if(!cell || (!this.CellSelection && !this.RowSelection)){
5430 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5431 cell = cell.findParent('td', false, true);
5434 if(!cell || typeof(cell) == 'undefined'){
5438 var row = cell.findParent('tr', false, true);
5440 if(!row || typeof(row) == 'undefined'){
5444 var cellIndex = cell.dom.cellIndex;
5445 var rowIndex = this.getRowIndex(row);
5447 if(this.CellSelection){
5448 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5451 if(this.RowSelection){
5452 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5456 sort : function(e,el)
5458 var col = Roo.get(el);
5460 if(!col.hasClass('sortable')){
5464 var sort = col.attr('sort');
5467 if(col.hasClass('glyphicon-arrow-up')){
5471 this.store.sortInfo = {field : sort, direction : dir};
5474 Roo.log("calling footer first");
5475 this.footer.onClick('first');
5478 this.store.load({ params : { start : 0 } });
5482 renderHeader : function()
5491 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5493 var config = cm.config[i];
5498 html: cm.getColumnHeader(i)
5501 if(typeof(config.tooltip) != 'undefined'){
5502 c.tooltip = config.tooltip;
5505 if(typeof(config.colspan) != 'undefined'){
5506 c.colspan = config.colspan;
5509 if(typeof(config.hidden) != 'undefined' && config.hidden){
5510 c.style += ' display:none;';
5513 if(typeof(config.dataIndex) != 'undefined'){
5514 c.sort = config.dataIndex;
5517 if(typeof(config.sortable) != 'undefined' && config.sortable){
5521 if(typeof(config.align) != 'undefined' && config.align.length){
5522 c.style += ' text-align:' + config.align + ';';
5525 if(typeof(config.width) != 'undefined'){
5526 c.style += ' width:' + config.width + 'px;';
5535 renderBody : function()
5545 colspan : this.cm.getColumnCount()
5555 renderFooter : function()
5565 colspan : this.cm.getColumnCount()
5579 Roo.log('ds onload');
5584 var ds = this.store;
5586 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5587 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5589 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5590 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5593 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5594 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5598 var tbody = this.mainBody;
5600 if(ds.getCount() > 0){
5601 ds.data.each(function(d,rowIndex){
5602 var row = this.renderRow(cm, ds, rowIndex);
5604 tbody.createChild(row);
5608 if(row.cellObjects.length){
5609 Roo.each(row.cellObjects, function(r){
5610 _this.renderCellObject(r);
5617 Roo.each(this.el.select('tbody td', true).elements, function(e){
5618 e.on('mouseover', _this.onMouseover, _this);
5621 Roo.each(this.el.select('tbody td', true).elements, function(e){
5622 e.on('mouseout', _this.onMouseout, _this);
5624 this.fireEvent('rowsrendered', this);
5625 //if(this.loadMask){
5626 // this.maskEl.hide();
5631 onUpdate : function(ds,record)
5633 this.refreshRow(record);
5636 onRemove : function(ds, record, index, isUpdate){
5637 if(isUpdate !== true){
5638 this.fireEvent("beforerowremoved", this, index, record);
5640 var bt = this.mainBody.dom;
5642 var rows = this.el.select('tbody > tr', true).elements;
5644 if(typeof(rows[index]) != 'undefined'){
5645 bt.removeChild(rows[index].dom);
5648 // if(bt.rows[index]){
5649 // bt.removeChild(bt.rows[index]);
5652 if(isUpdate !== true){
5653 //this.stripeRows(index);
5654 //this.syncRowHeights(index, index);
5656 this.fireEvent("rowremoved", this, index, record);
5660 onAdd : function(ds, records, rowIndex)
5662 //Roo.log('on Add called');
5663 // - note this does not handle multiple adding very well..
5664 var bt = this.mainBody.dom;
5665 for (var i =0 ; i < records.length;i++) {
5666 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5667 //Roo.log(records[i]);
5668 //Roo.log(this.store.getAt(rowIndex+i));
5669 this.insertRow(this.store, rowIndex + i, false);
5676 refreshRow : function(record){
5677 var ds = this.store, index;
5678 if(typeof record == 'number'){
5680 record = ds.getAt(index);
5682 index = ds.indexOf(record);
5684 this.insertRow(ds, index, true);
5685 this.onRemove(ds, record, index+1, true);
5686 //this.syncRowHeights(index, index);
5688 this.fireEvent("rowupdated", this, index, record);
5691 insertRow : function(dm, rowIndex, isUpdate){
5694 this.fireEvent("beforerowsinserted", this, rowIndex);
5696 //var s = this.getScrollState();
5697 var row = this.renderRow(this.cm, this.store, rowIndex);
5698 // insert before rowIndex..
5699 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5703 if(row.cellObjects.length){
5704 Roo.each(row.cellObjects, function(r){
5705 _this.renderCellObject(r);
5710 this.fireEvent("rowsinserted", this, rowIndex);
5711 //this.syncRowHeights(firstRow, lastRow);
5712 //this.stripeRows(firstRow);
5719 getRowDom : function(rowIndex)
5721 var rows = this.el.select('tbody > tr', true).elements;
5723 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5726 // returns the object tree for a tr..
5729 renderRow : function(cm, ds, rowIndex)
5732 var d = ds.getAt(rowIndex);
5739 var cellObjects = [];
5741 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5742 var config = cm.config[i];
5744 var renderer = cm.getRenderer(i);
5748 if(typeof(renderer) !== 'undefined'){
5749 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5751 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5752 // and are rendered into the cells after the row is rendered - using the id for the element.
5754 if(typeof(value) === 'object'){
5764 rowIndex : rowIndex,
5769 this.fireEvent('rowclass', this, rowcfg);
5773 cls : rowcfg.rowClass,
5775 html: (typeof(value) === 'object') ? '' : value
5782 if(typeof(config.colspan) != 'undefined'){
5783 td.colspan = config.colspan;
5786 if(typeof(config.hidden) != 'undefined' && config.hidden){
5787 td.style += ' display:none;';
5790 if(typeof(config.align) != 'undefined' && config.align.length){
5791 td.style += ' text-align:' + config.align + ';';
5794 if(typeof(config.width) != 'undefined'){
5795 td.style += ' width:' + config.width + 'px;';
5798 if(typeof(config.cursor) != 'undefined'){
5799 td.style += ' cursor:' + config.cursor + ';';
5806 row.cellObjects = cellObjects;
5814 onBeforeLoad : function()
5816 //Roo.log('ds onBeforeLoad');
5820 //if(this.loadMask){
5821 // this.maskEl.show();
5829 this.el.select('tbody', true).first().dom.innerHTML = '';
5832 * Show or hide a row.
5833 * @param {Number} rowIndex to show or hide
5834 * @param {Boolean} state hide
5836 setRowVisibility : function(rowIndex, state)
5838 var bt = this.mainBody.dom;
5840 var rows = this.el.select('tbody > tr', true).elements;
5842 if(typeof(rows[rowIndex]) == 'undefined'){
5845 rows[rowIndex].dom.style.display = state ? '' : 'none';
5849 getSelectionModel : function(){
5851 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5853 return this.selModel;
5856 * Render the Roo.bootstrap object from renderder
5858 renderCellObject : function(r)
5862 var t = r.cfg.render(r.container);
5865 Roo.each(r.cfg.cn, function(c){
5867 container: t.getChildContainer(),
5870 _this.renderCellObject(child);
5875 getRowIndex : function(row)
5879 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5902 * @class Roo.bootstrap.TableCell
5903 * @extends Roo.bootstrap.Component
5904 * Bootstrap TableCell class
5905 * @cfg {String} html cell contain text
5906 * @cfg {String} cls cell class
5907 * @cfg {String} tag cell tag (td|th) default td
5908 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5909 * @cfg {String} align Aligns the content in a cell
5910 * @cfg {String} axis Categorizes cells
5911 * @cfg {String} bgcolor Specifies the background color of a cell
5912 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5913 * @cfg {Number} colspan Specifies the number of columns a cell should span
5914 * @cfg {String} headers Specifies one or more header cells a cell is related to
5915 * @cfg {Number} height Sets the height of a cell
5916 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5917 * @cfg {Number} rowspan Sets the number of rows a cell should span
5918 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5919 * @cfg {String} valign Vertical aligns the content in a cell
5920 * @cfg {Number} width Specifies the width of a cell
5923 * Create a new TableCell
5924 * @param {Object} config The config object
5927 Roo.bootstrap.TableCell = function(config){
5928 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5931 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5951 getAutoCreate : function(){
5952 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5972 cfg.align=this.align
5978 cfg.bgcolor=this.bgcolor
5981 cfg.charoff=this.charoff
5984 cfg.colspan=this.colspan
5987 cfg.headers=this.headers
5990 cfg.height=this.height
5993 cfg.nowrap=this.nowrap
5996 cfg.rowspan=this.rowspan
5999 cfg.scope=this.scope
6002 cfg.valign=this.valign
6005 cfg.width=this.width
6024 * @class Roo.bootstrap.TableRow
6025 * @extends Roo.bootstrap.Component
6026 * Bootstrap TableRow class
6027 * @cfg {String} cls row class
6028 * @cfg {String} align Aligns the content in a table row
6029 * @cfg {String} bgcolor Specifies a background color for a table row
6030 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6031 * @cfg {String} valign Vertical aligns the content in a table row
6034 * Create a new TableRow
6035 * @param {Object} config The config object
6038 Roo.bootstrap.TableRow = function(config){
6039 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6042 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6050 getAutoCreate : function(){
6051 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6061 cfg.align = this.align;
6064 cfg.bgcolor = this.bgcolor;
6067 cfg.charoff = this.charoff;
6070 cfg.valign = this.valign;
6088 * @class Roo.bootstrap.TableBody
6089 * @extends Roo.bootstrap.Component
6090 * Bootstrap TableBody class
6091 * @cfg {String} cls element class
6092 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6093 * @cfg {String} align Aligns the content inside the element
6094 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6095 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6098 * Create a new TableBody
6099 * @param {Object} config The config object
6102 Roo.bootstrap.TableBody = function(config){
6103 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6106 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6114 getAutoCreate : function(){
6115 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6129 cfg.align = this.align;
6132 cfg.charoff = this.charoff;
6135 cfg.valign = this.valign;
6142 // initEvents : function()
6149 // this.store = Roo.factory(this.store, Roo.data);
6150 // this.store.on('load', this.onLoad, this);
6152 // this.store.load();
6156 // onLoad: function ()
6158 // this.fireEvent('load', this);
6168 * Ext JS Library 1.1.1
6169 * Copyright(c) 2006-2007, Ext JS, LLC.
6171 * Originally Released Under LGPL - original licence link has changed is not relivant.
6174 * <script type="text/javascript">
6177 // as we use this in bootstrap.
6178 Roo.namespace('Roo.form');
6180 * @class Roo.form.Action
6181 * Internal Class used to handle form actions
6183 * @param {Roo.form.BasicForm} el The form element or its id
6184 * @param {Object} config Configuration options
6189 // define the action interface
6190 Roo.form.Action = function(form, options){
6192 this.options = options || {};
6195 * Client Validation Failed
6198 Roo.form.Action.CLIENT_INVALID = 'client';
6200 * Server Validation Failed
6203 Roo.form.Action.SERVER_INVALID = 'server';
6205 * Connect to Server Failed
6208 Roo.form.Action.CONNECT_FAILURE = 'connect';
6210 * Reading Data from Server Failed
6213 Roo.form.Action.LOAD_FAILURE = 'load';
6215 Roo.form.Action.prototype = {
6217 failureType : undefined,
6218 response : undefined,
6222 run : function(options){
6227 success : function(response){
6232 handleResponse : function(response){
6236 // default connection failure
6237 failure : function(response){
6239 this.response = response;
6240 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6241 this.form.afterAction(this, false);
6244 processResponse : function(response){
6245 this.response = response;
6246 if(!response.responseText){
6249 this.result = this.handleResponse(response);
6253 // utility functions used internally
6254 getUrl : function(appendParams){
6255 var url = this.options.url || this.form.url || this.form.el.dom.action;
6257 var p = this.getParams();
6259 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6265 getMethod : function(){
6266 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6269 getParams : function(){
6270 var bp = this.form.baseParams;
6271 var p = this.options.params;
6273 if(typeof p == "object"){
6274 p = Roo.urlEncode(Roo.applyIf(p, bp));
6275 }else if(typeof p == 'string' && bp){
6276 p += '&' + Roo.urlEncode(bp);
6279 p = Roo.urlEncode(bp);
6284 createCallback : function(){
6286 success: this.success,
6287 failure: this.failure,
6289 timeout: (this.form.timeout*1000),
6290 upload: this.form.fileUpload ? this.success : undefined
6295 Roo.form.Action.Submit = function(form, options){
6296 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6299 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6302 haveProgress : false,
6303 uploadComplete : false,
6305 // uploadProgress indicator.
6306 uploadProgress : function()
6308 if (!this.form.progressUrl) {
6312 if (!this.haveProgress) {
6313 Roo.MessageBox.progress("Uploading", "Uploading");
6315 if (this.uploadComplete) {
6316 Roo.MessageBox.hide();
6320 this.haveProgress = true;
6322 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6324 var c = new Roo.data.Connection();
6326 url : this.form.progressUrl,
6331 success : function(req){
6332 //console.log(data);
6336 rdata = Roo.decode(req.responseText)
6338 Roo.log("Invalid data from server..");
6342 if (!rdata || !rdata.success) {
6344 Roo.MessageBox.alert(Roo.encode(rdata));
6347 var data = rdata.data;
6349 if (this.uploadComplete) {
6350 Roo.MessageBox.hide();
6355 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6356 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6359 this.uploadProgress.defer(2000,this);
6362 failure: function(data) {
6363 Roo.log('progress url failed ');
6374 // run get Values on the form, so it syncs any secondary forms.
6375 this.form.getValues();
6377 var o = this.options;
6378 var method = this.getMethod();
6379 var isPost = method == 'POST';
6380 if(o.clientValidation === false || this.form.isValid()){
6382 if (this.form.progressUrl) {
6383 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6384 (new Date() * 1) + '' + Math.random());
6389 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6390 form:this.form.el.dom,
6391 url:this.getUrl(!isPost),
6393 params:isPost ? this.getParams() : null,
6394 isUpload: this.form.fileUpload
6397 this.uploadProgress();
6399 }else if (o.clientValidation !== false){ // client validation failed
6400 this.failureType = Roo.form.Action.CLIENT_INVALID;
6401 this.form.afterAction(this, false);
6405 success : function(response)
6407 this.uploadComplete= true;
6408 if (this.haveProgress) {
6409 Roo.MessageBox.hide();
6413 var result = this.processResponse(response);
6414 if(result === true || result.success){
6415 this.form.afterAction(this, true);
6419 this.form.markInvalid(result.errors);
6420 this.failureType = Roo.form.Action.SERVER_INVALID;
6422 this.form.afterAction(this, false);
6424 failure : function(response)
6426 this.uploadComplete= true;
6427 if (this.haveProgress) {
6428 Roo.MessageBox.hide();
6431 this.response = response;
6432 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6433 this.form.afterAction(this, false);
6436 handleResponse : function(response){
6437 if(this.form.errorReader){
6438 var rs = this.form.errorReader.read(response);
6441 for(var i = 0, len = rs.records.length; i < len; i++) {
6442 var r = rs.records[i];
6446 if(errors.length < 1){
6450 success : rs.success,
6456 ret = Roo.decode(response.responseText);
6460 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6470 Roo.form.Action.Load = function(form, options){
6471 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6472 this.reader = this.form.reader;
6475 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6480 Roo.Ajax.request(Roo.apply(
6481 this.createCallback(), {
6482 method:this.getMethod(),
6483 url:this.getUrl(false),
6484 params:this.getParams()
6488 success : function(response){
6490 var result = this.processResponse(response);
6491 if(result === true || !result.success || !result.data){
6492 this.failureType = Roo.form.Action.LOAD_FAILURE;
6493 this.form.afterAction(this, false);
6496 this.form.clearInvalid();
6497 this.form.setValues(result.data);
6498 this.form.afterAction(this, true);
6501 handleResponse : function(response){
6502 if(this.form.reader){
6503 var rs = this.form.reader.read(response);
6504 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6506 success : rs.success,
6510 return Roo.decode(response.responseText);
6514 Roo.form.Action.ACTION_TYPES = {
6515 'load' : Roo.form.Action.Load,
6516 'submit' : Roo.form.Action.Submit
6525 * @class Roo.bootstrap.Form
6526 * @extends Roo.bootstrap.Component
6527 * Bootstrap Form class
6528 * @cfg {String} method GET | POST (default POST)
6529 * @cfg {String} labelAlign top | left (default top)
6530 * @cfg {String} align left | right - for navbars
6531 * @cfg {Boolean} loadMask load mask when submit (default true)
6536 * @param {Object} config The config object
6540 Roo.bootstrap.Form = function(config){
6541 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6544 * @event clientvalidation
6545 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6546 * @param {Form} this
6547 * @param {Boolean} valid true if the form has passed client-side validation
6549 clientvalidation: true,
6551 * @event beforeaction
6552 * Fires before any action is performed. Return false to cancel the action.
6553 * @param {Form} this
6554 * @param {Action} action The action to be performed
6558 * @event actionfailed
6559 * Fires when an action fails.
6560 * @param {Form} this
6561 * @param {Action} action The action that failed
6563 actionfailed : true,
6565 * @event actioncomplete
6566 * Fires when an action is completed.
6567 * @param {Form} this
6568 * @param {Action} action The action that completed
6570 actioncomplete : true
6575 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6578 * @cfg {String} method
6579 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6584 * The URL to use for form actions if one isn't supplied in the action options.
6587 * @cfg {Boolean} fileUpload
6588 * Set to true if this form is a file upload.
6592 * @cfg {Object} baseParams
6593 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6597 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6601 * @cfg {Sting} align (left|right) for navbar forms
6606 activeAction : null,
6609 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6610 * element by passing it or its id or mask the form itself by passing in true.
6613 waitMsgTarget : false,
6617 getAutoCreate : function(){
6621 method : this.method || 'POST',
6622 id : this.id || Roo.id(),
6625 if (this.parent().xtype.match(/^Nav/)) {
6626 cfg.cls = 'navbar-form navbar-' + this.align;
6630 if (this.labelAlign == 'left' ) {
6631 cfg.cls += ' form-horizontal';
6637 initEvents : function()
6639 this.el.on('submit', this.onSubmit, this);
6640 // this was added as random key presses on the form where triggering form submit.
6641 this.el.on('keypress', function(e) {
6642 if (e.getCharCode() != 13) {
6645 // we might need to allow it for textareas.. and some other items.
6646 // check e.getTarget().
6648 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6652 Roo.log("keypress blocked");
6660 onSubmit : function(e){
6665 * Returns true if client-side validation on the form is successful.
6668 isValid : function(){
6669 var items = this.getItems();
6671 items.each(function(f){
6680 * Returns true if any fields in this form have changed since their original load.
6683 isDirty : function(){
6685 var items = this.getItems();
6686 items.each(function(f){
6696 * Performs a predefined action (submit or load) or custom actions you define on this form.
6697 * @param {String} actionName The name of the action type
6698 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6699 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6700 * accept other config options):
6702 Property Type Description
6703 ---------------- --------------- ----------------------------------------------------------------------------------
6704 url String The url for the action (defaults to the form's url)
6705 method String The form method to use (defaults to the form's method, or POST if not defined)
6706 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6707 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6708 validate the form on the client (defaults to false)
6710 * @return {BasicForm} this
6712 doAction : function(action, options){
6713 if(typeof action == 'string'){
6714 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6716 if(this.fireEvent('beforeaction', this, action) !== false){
6717 this.beforeAction(action);
6718 action.run.defer(100, action);
6724 beforeAction : function(action){
6725 var o = action.options;
6728 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6730 // not really supported yet.. ??
6732 //if(this.waitMsgTarget === true){
6733 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6734 //}else if(this.waitMsgTarget){
6735 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6736 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6738 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6744 afterAction : function(action, success){
6745 this.activeAction = null;
6746 var o = action.options;
6748 //if(this.waitMsgTarget === true){
6750 //}else if(this.waitMsgTarget){
6751 // this.waitMsgTarget.unmask();
6753 // Roo.MessageBox.updateProgress(1);
6754 // Roo.MessageBox.hide();
6761 Roo.callback(o.success, o.scope, [this, action]);
6762 this.fireEvent('actioncomplete', this, action);
6766 // failure condition..
6767 // we have a scenario where updates need confirming.
6768 // eg. if a locking scenario exists..
6769 // we look for { errors : { needs_confirm : true }} in the response.
6771 (typeof(action.result) != 'undefined') &&
6772 (typeof(action.result.errors) != 'undefined') &&
6773 (typeof(action.result.errors.needs_confirm) != 'undefined')
6776 Roo.log("not supported yet");
6779 Roo.MessageBox.confirm(
6780 "Change requires confirmation",
6781 action.result.errorMsg,
6786 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6796 Roo.callback(o.failure, o.scope, [this, action]);
6797 // show an error message if no failed handler is set..
6798 if (!this.hasListener('actionfailed')) {
6799 Roo.log("need to add dialog support");
6801 Roo.MessageBox.alert("Error",
6802 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6803 action.result.errorMsg :
6804 "Saving Failed, please check your entries or try again"
6809 this.fireEvent('actionfailed', this, action);
6814 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6815 * @param {String} id The value to search for
6818 findField : function(id){
6819 var items = this.getItems();
6820 var field = items.get(id);
6822 items.each(function(f){
6823 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6830 return field || null;
6833 * Mark fields in this form invalid in bulk.
6834 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6835 * @return {BasicForm} this
6837 markInvalid : function(errors){
6838 if(errors instanceof Array){
6839 for(var i = 0, len = errors.length; i < len; i++){
6840 var fieldError = errors[i];
6841 var f = this.findField(fieldError.id);
6843 f.markInvalid(fieldError.msg);
6849 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6850 field.markInvalid(errors[id]);
6854 //Roo.each(this.childForms || [], function (f) {
6855 // f.markInvalid(errors);
6862 * Set values for fields in this form in bulk.
6863 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6864 * @return {BasicForm} this
6866 setValues : function(values){
6867 if(values instanceof Array){ // array of objects
6868 for(var i = 0, len = values.length; i < len; i++){
6870 var f = this.findField(v.id);
6872 f.setValue(v.value);
6873 if(this.trackResetOnLoad){
6874 f.originalValue = f.getValue();
6878 }else{ // object hash
6881 if(typeof values[id] != 'function' && (field = this.findField(id))){
6883 if (field.setFromData &&
6885 field.displayField &&
6886 // combos' with local stores can
6887 // be queried via setValue()
6888 // to set their value..
6889 (field.store && !field.store.isLocal)
6893 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6894 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6895 field.setFromData(sd);
6898 field.setValue(values[id]);
6902 if(this.trackResetOnLoad){
6903 field.originalValue = field.getValue();
6909 //Roo.each(this.childForms || [], function (f) {
6910 // f.setValues(values);
6917 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6918 * they are returned as an array.
6919 * @param {Boolean} asString
6922 getValues : function(asString){
6923 //if (this.childForms) {
6924 // copy values from the child forms
6925 // Roo.each(this.childForms, function (f) {
6926 // this.setValues(f.getValues());
6932 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6933 if(asString === true){
6936 return Roo.urlDecode(fs);
6940 * Returns the fields in this form as an object with key/value pairs.
6941 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6944 getFieldValues : function(with_hidden)
6946 var items = this.getItems();
6948 items.each(function(f){
6952 var v = f.getValue();
6953 if (f.inputType =='radio') {
6954 if (typeof(ret[f.getName()]) == 'undefined') {
6955 ret[f.getName()] = ''; // empty..
6958 if (!f.el.dom.checked) {
6966 // not sure if this supported any more..
6967 if ((typeof(v) == 'object') && f.getRawValue) {
6968 v = f.getRawValue() ; // dates..
6970 // combo boxes where name != hiddenName...
6971 if (f.name != f.getName()) {
6972 ret[f.name] = f.getRawValue();
6974 ret[f.getName()] = v;
6981 * Clears all invalid messages in this form.
6982 * @return {BasicForm} this
6984 clearInvalid : function(){
6985 var items = this.getItems();
6987 items.each(function(f){
6998 * @return {BasicForm} this
7001 var items = this.getItems();
7002 items.each(function(f){
7006 Roo.each(this.childForms || [], function (f) {
7013 getItems : function()
7015 var r=new Roo.util.MixedCollection(false, function(o){
7016 return o.id || (o.id = Roo.id());
7018 var iter = function(el) {
7025 Roo.each(el.items,function(e) {
7045 * Ext JS Library 1.1.1
7046 * Copyright(c) 2006-2007, Ext JS, LLC.
7048 * Originally Released Under LGPL - original licence link has changed is not relivant.
7051 * <script type="text/javascript">
7054 * @class Roo.form.VTypes
7055 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7058 Roo.form.VTypes = function(){
7059 // closure these in so they are only created once.
7060 var alpha = /^[a-zA-Z_]+$/;
7061 var alphanum = /^[a-zA-Z0-9_]+$/;
7062 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7063 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7065 // All these messages and functions are configurable
7068 * The function used to validate email addresses
7069 * @param {String} value The email address
7071 'email' : function(v){
7072 return email.test(v);
7075 * The error text to display when the email validation function returns false
7078 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7080 * The keystroke filter mask to be applied on email input
7083 'emailMask' : /[a-z0-9_\.\-@]/i,
7086 * The function used to validate URLs
7087 * @param {String} value The URL
7089 'url' : function(v){
7093 * The error text to display when the url validation function returns false
7096 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7099 * The function used to validate alpha values
7100 * @param {String} value The value
7102 'alpha' : function(v){
7103 return alpha.test(v);
7106 * The error text to display when the alpha validation function returns false
7109 'alphaText' : 'This field should only contain letters and _',
7111 * The keystroke filter mask to be applied on alpha input
7114 'alphaMask' : /[a-z_]/i,
7117 * The function used to validate alphanumeric values
7118 * @param {String} value The value
7120 'alphanum' : function(v){
7121 return alphanum.test(v);
7124 * The error text to display when the alphanumeric validation function returns false
7127 'alphanumText' : 'This field should only contain letters, numbers and _',
7129 * The keystroke filter mask to be applied on alphanumeric input
7132 'alphanumMask' : /[a-z0-9_]/i
7142 * @class Roo.bootstrap.Input
7143 * @extends Roo.bootstrap.Component
7144 * Bootstrap Input class
7145 * @cfg {Boolean} disabled is it disabled
7146 * @cfg {String} fieldLabel - the label associated
7147 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7148 * @cfg {String} name name of the input
7149 * @cfg {string} fieldLabel - the label associated
7150 * @cfg {string} inputType - input / file submit ...
7151 * @cfg {string} placeholder - placeholder to put in text.
7152 * @cfg {string} before - input group add on before
7153 * @cfg {string} after - input group add on after
7154 * @cfg {string} size - (lg|sm) or leave empty..
7155 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7156 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7157 * @cfg {Number} md colspan out of 12 for computer-sized screens
7158 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7159 * @cfg {string} value default value of the input
7160 * @cfg {Number} labelWidth set the width of label (0-12)
7161 * @cfg {String} labelAlign (top|left)
7162 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7163 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7165 * @cfg {String} align (left|center|right) Default left
7170 * Create a new Input
7171 * @param {Object} config The config object
7174 Roo.bootstrap.Input = function(config){
7175 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7180 * Fires when this field receives input focus.
7181 * @param {Roo.form.Field} this
7186 * Fires when this field loses input focus.
7187 * @param {Roo.form.Field} this
7192 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7193 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7194 * @param {Roo.form.Field} this
7195 * @param {Roo.EventObject} e The event object
7200 * Fires just before the field blurs if the field value has changed.
7201 * @param {Roo.form.Field} this
7202 * @param {Mixed} newValue The new value
7203 * @param {Mixed} oldValue The original value
7208 * Fires after the field has been marked as invalid.
7209 * @param {Roo.form.Field} this
7210 * @param {String} msg The validation message
7215 * Fires after the field has been validated with no errors.
7216 * @param {Roo.form.Field} this
7221 * Fires after the key up
7222 * @param {Roo.form.Field} this
7223 * @param {Roo.EventObject} e The event Object
7229 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7231 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7232 automatic validation (defaults to "keyup").
7234 validationEvent : "keyup",
7236 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7238 validateOnBlur : true,
7240 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7242 validationDelay : 250,
7244 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7246 focusClass : "x-form-focus", // not needed???
7250 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7252 invalidClass : "has-warning",
7255 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7257 validClass : "has-success",
7260 * @cfg {Boolean} hasFeedback (true|false) default true
7265 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7267 invalidFeedbackClass : "glyphicon-warning-sign",
7270 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7272 validFeedbackClass : "glyphicon-ok",
7275 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7277 selectOnFocus : false,
7280 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7284 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7289 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7291 disableKeyFilter : false,
7294 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7298 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7302 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7304 blankText : "This field is required",
7307 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7311 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7313 maxLength : Number.MAX_VALUE,
7315 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7317 minLengthText : "The minimum length for this field is {0}",
7319 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7321 maxLengthText : "The maximum length for this field is {0}",
7325 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7326 * If available, this function will be called only after the basic validators all return true, and will be passed the
7327 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7331 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7332 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7333 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7337 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7341 autocomplete: false,
7360 formatedValue : false,
7362 parentLabelAlign : function()
7365 while (parent.parent()) {
7366 parent = parent.parent();
7367 if (typeof(parent.labelAlign) !='undefined') {
7368 return parent.labelAlign;
7375 getAutoCreate : function(){
7377 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7383 if(this.inputType != 'hidden'){
7384 cfg.cls = 'form-group' //input-group
7390 type : this.inputType,
7392 cls : 'form-control',
7393 placeholder : this.placeholder || '',
7394 autocomplete : this.autocomplete || 'new-password'
7399 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7402 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7403 input.maxLength = this.maxLength;
7406 if (this.disabled) {
7407 input.disabled=true;
7410 if (this.readOnly) {
7411 input.readonly=true;
7415 input.name = this.name;
7418 input.cls += ' input-' + this.size;
7421 ['xs','sm','md','lg'].map(function(size){
7422 if (settings[size]) {
7423 cfg.cls += ' col-' + size + '-' + settings[size];
7427 var inputblock = input;
7429 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7433 cls: 'glyphicon form-control-feedback'
7437 cls : 'has-feedback',
7445 // var inputblock = input;
7447 if (this.before || this.after) {
7450 cls : 'input-group',
7454 if (this.before && typeof(this.before) == 'string') {
7456 inputblock.cn.push({
7458 cls : 'roo-input-before input-group-addon',
7462 if (this.before && typeof(this.before) == 'object') {
7463 this.before = Roo.factory(this.before);
7464 Roo.log(this.before);
7465 inputblock.cn.push({
7467 cls : 'roo-input-before input-group-' +
7468 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7472 inputblock.cn.push(input);
7474 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7475 inputblock.cls += ' has-feedback';
7476 inputblock.cn.push(feedback);
7479 if (this.after && typeof(this.after) == 'string') {
7480 inputblock.cn.push({
7482 cls : 'roo-input-after input-group-addon',
7486 if (this.after && typeof(this.after) == 'object') {
7487 this.after = Roo.factory(this.after);
7488 Roo.log(this.after);
7489 inputblock.cn.push({
7491 cls : 'roo-input-after input-group-' +
7492 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7497 if (align ==='left' && this.fieldLabel.length) {
7498 Roo.log("left and has label");
7504 cls : 'control-label col-sm-' + this.labelWidth,
7505 html : this.fieldLabel
7509 cls : "col-sm-" + (12 - this.labelWidth),
7516 } else if ( this.fieldLabel.length) {
7522 //cls : 'input-group-addon',
7523 html : this.fieldLabel
7533 Roo.log(" no label && no align");
7542 Roo.log('input-parentType: ' + this.parentType);
7544 if (this.parentType === 'Navbar' && this.parent().bar) {
7545 cfg.cls += ' navbar-form';
7553 * return the real input element.
7555 inputEl: function ()
7557 return this.el.select('input.form-control',true).first();
7560 tooltipEl : function()
7562 return this.inputEl();
7565 setDisabled : function(v)
7567 var i = this.inputEl().dom;
7569 i.removeAttribute('disabled');
7573 i.setAttribute('disabled','true');
7575 initEvents : function()
7578 this.inputEl().on("keydown" , this.fireKey, this);
7579 this.inputEl().on("focus", this.onFocus, this);
7580 this.inputEl().on("blur", this.onBlur, this);
7582 this.inputEl().relayEvent('keyup', this);
7584 // reference to original value for reset
7585 this.originalValue = this.getValue();
7586 //Roo.form.TextField.superclass.initEvents.call(this);
7587 if(this.validationEvent == 'keyup'){
7588 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7589 this.inputEl().on('keyup', this.filterValidation, this);
7591 else if(this.validationEvent !== false){
7592 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7595 if(this.selectOnFocus){
7596 this.on("focus", this.preFocus, this);
7599 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7600 this.inputEl().on("keypress", this.filterKeys, this);
7603 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7604 this.el.on("click", this.autoSize, this);
7607 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7608 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7611 if (typeof(this.before) == 'object') {
7612 this.before.render(this.el.select('.roo-input-before',true).first());
7614 if (typeof(this.after) == 'object') {
7615 this.after.render(this.el.select('.roo-input-after',true).first());
7620 filterValidation : function(e){
7621 if(!e.isNavKeyPress()){
7622 this.validationTask.delay(this.validationDelay);
7626 * Validates the field value
7627 * @return {Boolean} True if the value is valid, else false
7629 validate : function(){
7630 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7631 if(this.disabled || this.validateValue(this.getRawValue())){
7642 * Validates a value according to the field's validation rules and marks the field as invalid
7643 * if the validation fails
7644 * @param {Mixed} value The value to validate
7645 * @return {Boolean} True if the value is valid, else false
7647 validateValue : function(value){
7648 if(value.length < 1) { // if it's blank
7649 if(this.allowBlank){
7655 if(value.length < this.minLength){
7658 if(value.length > this.maxLength){
7662 var vt = Roo.form.VTypes;
7663 if(!vt[this.vtype](value, this)){
7667 if(typeof this.validator == "function"){
7668 var msg = this.validator(value);
7674 if(this.regex && !this.regex.test(value)){
7684 fireKey : function(e){
7685 //Roo.log('field ' + e.getKey());
7686 if(e.isNavKeyPress()){
7687 this.fireEvent("specialkey", this, e);
7690 focus : function (selectText){
7692 this.inputEl().focus();
7693 if(selectText === true){
7694 this.inputEl().dom.select();
7700 onFocus : function(){
7701 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7702 // this.el.addClass(this.focusClass);
7705 this.hasFocus = true;
7706 this.startValue = this.getValue();
7707 this.fireEvent("focus", this);
7711 beforeBlur : Roo.emptyFn,
7715 onBlur : function(){
7717 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7718 //this.el.removeClass(this.focusClass);
7720 this.hasFocus = false;
7721 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7724 var v = this.getValue();
7725 if(String(v) !== String(this.startValue)){
7726 this.fireEvent('change', this, v, this.startValue);
7728 this.fireEvent("blur", this);
7732 * Resets the current field value to the originally loaded value and clears any validation messages
7735 this.setValue(this.originalValue);
7739 * Returns the name of the field
7740 * @return {Mixed} name The name field
7742 getName: function(){
7746 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7747 * @return {Mixed} value The field value
7749 getValue : function(){
7751 var v = this.inputEl().getValue();
7756 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7757 * @return {Mixed} value The field value
7759 getRawValue : function(){
7760 var v = this.inputEl().getValue();
7766 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7767 * @param {Mixed} value The value to set
7769 setRawValue : function(v){
7770 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7773 selectText : function(start, end){
7774 var v = this.getRawValue();
7776 start = start === undefined ? 0 : start;
7777 end = end === undefined ? v.length : end;
7778 var d = this.inputEl().dom;
7779 if(d.setSelectionRange){
7780 d.setSelectionRange(start, end);
7781 }else if(d.createTextRange){
7782 var range = d.createTextRange();
7783 range.moveStart("character", start);
7784 range.moveEnd("character", v.length-end);
7791 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7792 * @param {Mixed} value The value to set
7794 setValue : function(v){
7797 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7803 processValue : function(value){
7804 if(this.stripCharsRe){
7805 var newValue = value.replace(this.stripCharsRe, '');
7806 if(newValue !== value){
7807 this.setRawValue(newValue);
7814 preFocus : function(){
7816 if(this.selectOnFocus){
7817 this.inputEl().dom.select();
7820 filterKeys : function(e){
7822 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7825 var c = e.getCharCode(), cc = String.fromCharCode(c);
7826 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7829 if(!this.maskRe.test(cc)){
7834 * Clear any invalid styles/messages for this field
7836 clearInvalid : function(){
7838 if(!this.el || this.preventMark){ // not rendered
7841 this.el.removeClass(this.invalidClass);
7843 this.fireEvent('valid', this);
7847 * Mark this field as valid
7849 markValid : function(){
7850 if(!this.el || this.preventMark){ // not rendered
7854 this.el.removeClass([this.invalidClass, this.validClass]);
7856 if(this.disabled || this.allowBlank){
7860 this.el.addClass(this.validClass);
7862 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7864 var feedback = this.el.select('.form-control-feedback', true).first();
7867 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7868 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7873 this.fireEvent('valid', this);
7877 * Mark this field as invalid
7878 * @param {String} msg The validation message
7880 markInvalid : function(msg){
7881 if(!this.el || this.preventMark){ // not rendered
7885 this.el.removeClass([this.invalidClass, this.validClass]);
7887 if(this.disabled || this.allowBlank){
7891 this.el.addClass(this.invalidClass);
7893 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7895 var feedback = this.el.select('.form-control-feedback', true).first();
7898 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7900 if(this.getValue().length){
7901 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7908 this.fireEvent('invalid', this, msg);
7911 SafariOnKeyDown : function(event)
7913 // this is a workaround for a password hang bug on chrome/ webkit.
7915 var isSelectAll = false;
7917 if(this.inputEl().dom.selectionEnd > 0){
7918 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7920 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7921 event.preventDefault();
7926 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
7928 event.preventDefault();
7929 // this is very hacky as keydown always get's upper case.
7931 var cc = String.fromCharCode(event.getCharCode());
7932 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7936 adjustWidth : function(tag, w){
7937 tag = tag.toLowerCase();
7938 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7939 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7943 if(tag == 'textarea'){
7946 }else if(Roo.isOpera){
7950 if(tag == 'textarea'){
7969 * @class Roo.bootstrap.TextArea
7970 * @extends Roo.bootstrap.Input
7971 * Bootstrap TextArea class
7972 * @cfg {Number} cols Specifies the visible width of a text area
7973 * @cfg {Number} rows Specifies the visible number of lines in a text area
7974 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7975 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7976 * @cfg {string} html text
7979 * Create a new TextArea
7980 * @param {Object} config The config object
7983 Roo.bootstrap.TextArea = function(config){
7984 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7988 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7998 getAutoCreate : function(){
8000 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8011 value : this.value || '',
8012 html: this.html || '',
8013 cls : 'form-control',
8014 placeholder : this.placeholder || ''
8018 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8019 input.maxLength = this.maxLength;
8023 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8027 input.cols = this.cols;
8030 if (this.readOnly) {
8031 input.readonly = true;
8035 input.name = this.name;
8039 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8043 ['xs','sm','md','lg'].map(function(size){
8044 if (settings[size]) {
8045 cfg.cls += ' col-' + size + '-' + settings[size];
8049 var inputblock = input;
8051 if(this.hasFeedback && !this.allowBlank){
8055 cls: 'glyphicon form-control-feedback'
8059 cls : 'has-feedback',
8068 if (this.before || this.after) {
8071 cls : 'input-group',
8075 inputblock.cn.push({
8077 cls : 'input-group-addon',
8082 inputblock.cn.push(input);
8084 if(this.hasFeedback && !this.allowBlank){
8085 inputblock.cls += ' has-feedback';
8086 inputblock.cn.push(feedback);
8090 inputblock.cn.push({
8092 cls : 'input-group-addon',
8099 if (align ==='left' && this.fieldLabel.length) {
8100 Roo.log("left and has label");
8106 cls : 'control-label col-sm-' + this.labelWidth,
8107 html : this.fieldLabel
8111 cls : "col-sm-" + (12 - this.labelWidth),
8118 } else if ( this.fieldLabel.length) {
8124 //cls : 'input-group-addon',
8125 html : this.fieldLabel
8135 Roo.log(" no label && no align");
8145 if (this.disabled) {
8146 input.disabled=true;
8153 * return the real textarea element.
8155 inputEl: function ()
8157 return this.el.select('textarea.form-control',true).first();
8165 * trigger field - base class for combo..
8170 * @class Roo.bootstrap.TriggerField
8171 * @extends Roo.bootstrap.Input
8172 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8173 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8174 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8175 * for which you can provide a custom implementation. For example:
8177 var trigger = new Roo.bootstrap.TriggerField();
8178 trigger.onTriggerClick = myTriggerFn;
8179 trigger.applyTo('my-field');
8182 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8183 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8184 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8185 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8186 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8189 * Create a new TriggerField.
8190 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8191 * to the base TextField)
8193 Roo.bootstrap.TriggerField = function(config){
8194 this.mimicing = false;
8195 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8198 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8200 * @cfg {String} triggerClass A CSS class to apply to the trigger
8203 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8207 /** @cfg {Boolean} grow @hide */
8208 /** @cfg {Number} growMin @hide */
8209 /** @cfg {Number} growMax @hide */
8215 autoSize: Roo.emptyFn,
8222 actionMode : 'wrap',
8227 getAutoCreate : function(){
8229 var align = this.labelAlign || this.parentLabelAlign();
8234 cls: 'form-group' //input-group
8241 type : this.inputType,
8242 cls : 'form-control',
8243 autocomplete: 'new-password',
8244 placeholder : this.placeholder || ''
8248 input.name = this.name;
8251 input.cls += ' input-' + this.size;
8254 if (this.disabled) {
8255 input.disabled=true;
8258 var inputblock = input;
8260 if(this.hasFeedback && !this.allowBlank){
8264 cls: 'glyphicon form-control-feedback'
8268 cls : 'has-feedback',
8276 if (this.before || this.after) {
8279 cls : 'input-group',
8283 inputblock.cn.push({
8285 cls : 'input-group-addon',
8290 inputblock.cn.push(input);
8292 if(this.hasFeedback && !this.allowBlank){
8293 inputblock.cls += ' has-feedback';
8294 inputblock.cn.push(feedback);
8298 inputblock.cn.push({
8300 cls : 'input-group-addon',
8313 cls: 'form-hidden-field'
8321 Roo.log('multiple');
8329 cls: 'form-hidden-field'
8333 cls: 'select2-choices',
8337 cls: 'select2-search-field',
8350 cls: 'select2-container input-group',
8355 // cls: 'typeahead typeahead-long dropdown-menu',
8356 // style: 'display:none'
8361 if(!this.multiple && this.showToggleBtn){
8367 if (this.caret != false) {
8370 cls: 'fa fa-' + this.caret
8377 cls : 'input-group-addon btn dropdown-toggle',
8382 cls: 'combobox-clear',
8396 combobox.cls += ' select2-container-multi';
8399 if (align ==='left' && this.fieldLabel.length) {
8401 Roo.log("left and has label");
8407 cls : 'control-label col-sm-' + this.labelWidth,
8408 html : this.fieldLabel
8412 cls : "col-sm-" + (12 - this.labelWidth),
8419 } else if ( this.fieldLabel.length) {
8425 //cls : 'input-group-addon',
8426 html : this.fieldLabel
8436 Roo.log(" no label && no align");
8443 ['xs','sm','md','lg'].map(function(size){
8444 if (settings[size]) {
8445 cfg.cls += ' col-' + size + '-' + settings[size];
8456 onResize : function(w, h){
8457 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8458 // if(typeof w == 'number'){
8459 // var x = w - this.trigger.getWidth();
8460 // this.inputEl().setWidth(this.adjustWidth('input', x));
8461 // this.trigger.setStyle('left', x+'px');
8466 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8469 getResizeEl : function(){
8470 return this.inputEl();
8474 getPositionEl : function(){
8475 return this.inputEl();
8479 alignErrorIcon : function(){
8480 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8484 initEvents : function(){
8488 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8489 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8490 if(!this.multiple && this.showToggleBtn){
8491 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8492 if(this.hideTrigger){
8493 this.trigger.setDisplayed(false);
8495 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8499 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8502 //this.trigger.addClassOnOver('x-form-trigger-over');
8503 //this.trigger.addClassOnClick('x-form-trigger-click');
8506 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8510 createList : function()
8512 this.list = Roo.get(document.body).createChild({
8514 cls: 'typeahead typeahead-long dropdown-menu',
8515 style: 'display:none'
8518 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8523 initTrigger : function(){
8528 onDestroy : function(){
8530 this.trigger.removeAllListeners();
8531 // this.trigger.remove();
8534 // this.wrap.remove();
8536 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8540 onFocus : function(){
8541 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8544 this.wrap.addClass('x-trigger-wrap-focus');
8545 this.mimicing = true;
8546 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8547 if(this.monitorTab){
8548 this.el.on("keydown", this.checkTab, this);
8555 checkTab : function(e){
8556 if(e.getKey() == e.TAB){
8562 onBlur : function(){
8567 mimicBlur : function(e, t){
8569 if(!this.wrap.contains(t) && this.validateBlur()){
8576 triggerBlur : function(){
8577 this.mimicing = false;
8578 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8579 if(this.monitorTab){
8580 this.el.un("keydown", this.checkTab, this);
8582 //this.wrap.removeClass('x-trigger-wrap-focus');
8583 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8587 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8588 validateBlur : function(e, t){
8593 onDisable : function(){
8594 this.inputEl().dom.disabled = true;
8595 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8597 // this.wrap.addClass('x-item-disabled');
8602 onEnable : function(){
8603 this.inputEl().dom.disabled = false;
8604 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8606 // this.el.removeClass('x-item-disabled');
8611 onShow : function(){
8612 var ae = this.getActionEl();
8615 ae.dom.style.display = '';
8616 ae.dom.style.visibility = 'visible';
8622 onHide : function(){
8623 var ae = this.getActionEl();
8624 ae.dom.style.display = 'none';
8628 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8629 * by an implementing function.
8631 * @param {EventObject} e
8633 onTriggerClick : Roo.emptyFn
8637 * Ext JS Library 1.1.1
8638 * Copyright(c) 2006-2007, Ext JS, LLC.
8640 * Originally Released Under LGPL - original licence link has changed is not relivant.
8643 * <script type="text/javascript">
8648 * @class Roo.data.SortTypes
8650 * Defines the default sorting (casting?) comparison functions used when sorting data.
8652 Roo.data.SortTypes = {
8654 * Default sort that does nothing
8655 * @param {Mixed} s The value being converted
8656 * @return {Mixed} The comparison value
8663 * The regular expression used to strip tags
8667 stripTagsRE : /<\/?[^>]+>/gi,
8670 * Strips all HTML tags to sort on text only
8671 * @param {Mixed} s The value being converted
8672 * @return {String} The comparison value
8674 asText : function(s){
8675 return String(s).replace(this.stripTagsRE, "");
8679 * Strips all HTML tags to sort on text only - Case insensitive
8680 * @param {Mixed} s The value being converted
8681 * @return {String} The comparison value
8683 asUCText : function(s){
8684 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8688 * Case insensitive string
8689 * @param {Mixed} s The value being converted
8690 * @return {String} The comparison value
8692 asUCString : function(s) {
8693 return String(s).toUpperCase();
8698 * @param {Mixed} s The value being converted
8699 * @return {Number} The comparison value
8701 asDate : function(s) {
8705 if(s instanceof Date){
8708 return Date.parse(String(s));
8713 * @param {Mixed} s The value being converted
8714 * @return {Float} The comparison value
8716 asFloat : function(s) {
8717 var val = parseFloat(String(s).replace(/,/g, ""));
8718 if(isNaN(val)) val = 0;
8724 * @param {Mixed} s The value being converted
8725 * @return {Number} The comparison value
8727 asInt : function(s) {
8728 var val = parseInt(String(s).replace(/,/g, ""));
8729 if(isNaN(val)) val = 0;
8734 * Ext JS Library 1.1.1
8735 * Copyright(c) 2006-2007, Ext JS, LLC.
8737 * Originally Released Under LGPL - original licence link has changed is not relivant.
8740 * <script type="text/javascript">
8744 * @class Roo.data.Record
8745 * Instances of this class encapsulate both record <em>definition</em> information, and record
8746 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8747 * to access Records cached in an {@link Roo.data.Store} object.<br>
8749 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8750 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8753 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8755 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8756 * {@link #create}. The parameters are the same.
8757 * @param {Array} data An associative Array of data values keyed by the field name.
8758 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8759 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8760 * not specified an integer id is generated.
8762 Roo.data.Record = function(data, id){
8763 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8768 * Generate a constructor for a specific record layout.
8769 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8770 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8771 * Each field definition object may contain the following properties: <ul>
8772 * <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,
8773 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8774 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8775 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8776 * is being used, then this is a string containing the javascript expression to reference the data relative to
8777 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8778 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8779 * this may be omitted.</p></li>
8780 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8781 * <ul><li>auto (Default, implies no conversion)</li>
8786 * <li>date</li></ul></p></li>
8787 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8788 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8789 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8790 * by the Reader into an object that will be stored in the Record. It is passed the
8791 * following parameters:<ul>
8792 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8794 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8796 * <br>usage:<br><pre><code>
8797 var TopicRecord = Roo.data.Record.create(
8798 {name: 'title', mapping: 'topic_title'},
8799 {name: 'author', mapping: 'username'},
8800 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8801 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8802 {name: 'lastPoster', mapping: 'user2'},
8803 {name: 'excerpt', mapping: 'post_text'}
8806 var myNewRecord = new TopicRecord({
8807 title: 'Do my job please',
8810 lastPost: new Date(),
8811 lastPoster: 'Animal',
8812 excerpt: 'No way dude!'
8814 myStore.add(myNewRecord);
8819 Roo.data.Record.create = function(o){
8821 f.superclass.constructor.apply(this, arguments);
8823 Roo.extend(f, Roo.data.Record);
8824 var p = f.prototype;
8825 p.fields = new Roo.util.MixedCollection(false, function(field){
8828 for(var i = 0, len = o.length; i < len; i++){
8829 p.fields.add(new Roo.data.Field(o[i]));
8831 f.getField = function(name){
8832 return p.fields.get(name);
8837 Roo.data.Record.AUTO_ID = 1000;
8838 Roo.data.Record.EDIT = 'edit';
8839 Roo.data.Record.REJECT = 'reject';
8840 Roo.data.Record.COMMIT = 'commit';
8842 Roo.data.Record.prototype = {
8844 * Readonly flag - true if this record has been modified.
8853 join : function(store){
8858 * Set the named field to the specified value.
8859 * @param {String} name The name of the field to set.
8860 * @param {Object} value The value to set the field to.
8862 set : function(name, value){
8863 if(this.data[name] == value){
8870 if(typeof this.modified[name] == 'undefined'){
8871 this.modified[name] = this.data[name];
8873 this.data[name] = value;
8874 if(!this.editing && this.store){
8875 this.store.afterEdit(this);
8880 * Get the value of the named field.
8881 * @param {String} name The name of the field to get the value of.
8882 * @return {Object} The value of the field.
8884 get : function(name){
8885 return this.data[name];
8889 beginEdit : function(){
8890 this.editing = true;
8895 cancelEdit : function(){
8896 this.editing = false;
8897 delete this.modified;
8901 endEdit : function(){
8902 this.editing = false;
8903 if(this.dirty && this.store){
8904 this.store.afterEdit(this);
8909 * Usually called by the {@link Roo.data.Store} which owns the Record.
8910 * Rejects all changes made to the Record since either creation, or the last commit operation.
8911 * Modified fields are reverted to their original values.
8913 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8914 * of reject operations.
8916 reject : function(){
8917 var m = this.modified;
8919 if(typeof m[n] != "function"){
8920 this.data[n] = m[n];
8924 delete this.modified;
8925 this.editing = false;
8927 this.store.afterReject(this);
8932 * Usually called by the {@link Roo.data.Store} which owns the Record.
8933 * Commits all changes made to the Record since either creation, or the last commit operation.
8935 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8936 * of commit operations.
8938 commit : function(){
8940 delete this.modified;
8941 this.editing = false;
8943 this.store.afterCommit(this);
8948 hasError : function(){
8949 return this.error != null;
8953 clearError : function(){
8958 * Creates a copy of this record.
8959 * @param {String} id (optional) A new record id if you don't want to use this record's id
8962 copy : function(newId) {
8963 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8967 * Ext JS Library 1.1.1
8968 * Copyright(c) 2006-2007, Ext JS, LLC.
8970 * Originally Released Under LGPL - original licence link has changed is not relivant.
8973 * <script type="text/javascript">
8979 * @class Roo.data.Store
8980 * @extends Roo.util.Observable
8981 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8982 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8984 * 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
8985 * has no knowledge of the format of the data returned by the Proxy.<br>
8987 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8988 * instances from the data object. These records are cached and made available through accessor functions.
8990 * Creates a new Store.
8991 * @param {Object} config A config object containing the objects needed for the Store to access data,
8992 * and read the data into Records.
8994 Roo.data.Store = function(config){
8995 this.data = new Roo.util.MixedCollection(false);
8996 this.data.getKey = function(o){
8999 this.baseParams = {};
9006 "multisort" : "_multisort"
9009 if(config && config.data){
9010 this.inlineData = config.data;
9014 Roo.apply(this, config);
9016 if(this.reader){ // reader passed
9017 this.reader = Roo.factory(this.reader, Roo.data);
9018 this.reader.xmodule = this.xmodule || false;
9019 if(!this.recordType){
9020 this.recordType = this.reader.recordType;
9022 if(this.reader.onMetaChange){
9023 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9027 if(this.recordType){
9028 this.fields = this.recordType.prototype.fields;
9034 * @event datachanged
9035 * Fires when the data cache has changed, and a widget which is using this Store
9036 * as a Record cache should refresh its view.
9037 * @param {Store} this
9042 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9043 * @param {Store} this
9044 * @param {Object} meta The JSON metadata
9049 * Fires when Records have been added to the Store
9050 * @param {Store} this
9051 * @param {Roo.data.Record[]} records The array of Records added
9052 * @param {Number} index The index at which the record(s) were added
9057 * Fires when a Record has been removed from the Store
9058 * @param {Store} this
9059 * @param {Roo.data.Record} record The Record that was removed
9060 * @param {Number} index The index at which the record was removed
9065 * Fires when a Record has been updated
9066 * @param {Store} this
9067 * @param {Roo.data.Record} record The Record that was updated
9068 * @param {String} operation The update operation being performed. Value may be one of:
9070 Roo.data.Record.EDIT
9071 Roo.data.Record.REJECT
9072 Roo.data.Record.COMMIT
9078 * Fires when the data cache has been cleared.
9079 * @param {Store} this
9084 * Fires before a request is made for a new data object. If the beforeload handler returns false
9085 * the load action will be canceled.
9086 * @param {Store} this
9087 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9091 * @event beforeloadadd
9092 * Fires after a new set of Records has been loaded.
9093 * @param {Store} this
9094 * @param {Roo.data.Record[]} records The Records that were loaded
9095 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9097 beforeloadadd : true,
9100 * Fires after a new set of Records has been loaded, before they are added to the store.
9101 * @param {Store} this
9102 * @param {Roo.data.Record[]} records The Records that were loaded
9103 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9104 * @params {Object} return from reader
9108 * @event loadexception
9109 * Fires if an exception occurs in the Proxy during loading.
9110 * Called with the signature of the Proxy's "loadexception" event.
9111 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9114 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9115 * @param {Object} load options
9116 * @param {Object} jsonData from your request (normally this contains the Exception)
9118 loadexception : true
9122 this.proxy = Roo.factory(this.proxy, Roo.data);
9123 this.proxy.xmodule = this.xmodule || false;
9124 this.relayEvents(this.proxy, ["loadexception"]);
9126 this.sortToggle = {};
9127 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9129 Roo.data.Store.superclass.constructor.call(this);
9131 if(this.inlineData){
9132 this.loadData(this.inlineData);
9133 delete this.inlineData;
9137 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9139 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9140 * without a remote query - used by combo/forms at present.
9144 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9147 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9150 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9151 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9154 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9155 * on any HTTP request
9158 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9161 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9165 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9166 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9171 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9172 * loaded or when a record is removed. (defaults to false).
9174 pruneModifiedRecords : false,
9180 * Add Records to the Store and fires the add event.
9181 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9183 add : function(records){
9184 records = [].concat(records);
9185 for(var i = 0, len = records.length; i < len; i++){
9186 records[i].join(this);
9188 var index = this.data.length;
9189 this.data.addAll(records);
9190 this.fireEvent("add", this, records, index);
9194 * Remove a Record from the Store and fires the remove event.
9195 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9197 remove : function(record){
9198 var index = this.data.indexOf(record);
9199 this.data.removeAt(index);
9200 if(this.pruneModifiedRecords){
9201 this.modified.remove(record);
9203 this.fireEvent("remove", this, record, index);
9207 * Remove all Records from the Store and fires the clear event.
9209 removeAll : function(){
9211 if(this.pruneModifiedRecords){
9214 this.fireEvent("clear", this);
9218 * Inserts Records to the Store at the given index and fires the add event.
9219 * @param {Number} index The start index at which to insert the passed Records.
9220 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9222 insert : function(index, records){
9223 records = [].concat(records);
9224 for(var i = 0, len = records.length; i < len; i++){
9225 this.data.insert(index, records[i]);
9226 records[i].join(this);
9228 this.fireEvent("add", this, records, index);
9232 * Get the index within the cache of the passed Record.
9233 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9234 * @return {Number} The index of the passed Record. Returns -1 if not found.
9236 indexOf : function(record){
9237 return this.data.indexOf(record);
9241 * Get the index within the cache of the Record with the passed id.
9242 * @param {String} id The id of the Record to find.
9243 * @return {Number} The index of the Record. Returns -1 if not found.
9245 indexOfId : function(id){
9246 return this.data.indexOfKey(id);
9250 * Get the Record with the specified id.
9251 * @param {String} id The id of the Record to find.
9252 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9254 getById : function(id){
9255 return this.data.key(id);
9259 * Get the Record at the specified index.
9260 * @param {Number} index The index of the Record to find.
9261 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9263 getAt : function(index){
9264 return this.data.itemAt(index);
9268 * Returns a range of Records between specified indices.
9269 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9270 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9271 * @return {Roo.data.Record[]} An array of Records
9273 getRange : function(start, end){
9274 return this.data.getRange(start, end);
9278 storeOptions : function(o){
9279 o = Roo.apply({}, o);
9282 this.lastOptions = o;
9286 * Loads the Record cache from the configured Proxy using the configured Reader.
9288 * If using remote paging, then the first load call must specify the <em>start</em>
9289 * and <em>limit</em> properties in the options.params property to establish the initial
9290 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9292 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9293 * and this call will return before the new data has been loaded. Perform any post-processing
9294 * in a callback function, or in a "load" event handler.</strong>
9296 * @param {Object} options An object containing properties which control loading options:<ul>
9297 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9298 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9299 * passed the following arguments:<ul>
9300 * <li>r : Roo.data.Record[]</li>
9301 * <li>options: Options object from the load call</li>
9302 * <li>success: Boolean success indicator</li></ul></li>
9303 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9304 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9307 load : function(options){
9308 options = options || {};
9309 if(this.fireEvent("beforeload", this, options) !== false){
9310 this.storeOptions(options);
9311 var p = Roo.apply(options.params || {}, this.baseParams);
9312 // if meta was not loaded from remote source.. try requesting it.
9313 if (!this.reader.metaFromRemote) {
9316 if(this.sortInfo && this.remoteSort){
9317 var pn = this.paramNames;
9318 p[pn["sort"]] = this.sortInfo.field;
9319 p[pn["dir"]] = this.sortInfo.direction;
9321 if (this.multiSort) {
9322 var pn = this.paramNames;
9323 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9326 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9331 * Reloads the Record cache from the configured Proxy using the configured Reader and
9332 * the options from the last load operation performed.
9333 * @param {Object} options (optional) An object containing properties which may override the options
9334 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9335 * the most recently used options are reused).
9337 reload : function(options){
9338 this.load(Roo.applyIf(options||{}, this.lastOptions));
9342 // Called as a callback by the Reader during a load operation.
9343 loadRecords : function(o, options, success){
9344 if(!o || success === false){
9345 if(success !== false){
9346 this.fireEvent("load", this, [], options, o);
9348 if(options.callback){
9349 options.callback.call(options.scope || this, [], options, false);
9353 // if data returned failure - throw an exception.
9354 if (o.success === false) {
9355 // show a message if no listener is registered.
9356 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9357 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9359 // loadmask wil be hooked into this..
9360 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9363 var r = o.records, t = o.totalRecords || r.length;
9365 this.fireEvent("beforeloadadd", this, r, options, o);
9367 if(!options || options.add !== true){
9368 if(this.pruneModifiedRecords){
9371 for(var i = 0, len = r.length; i < len; i++){
9375 this.data = this.snapshot;
9376 delete this.snapshot;
9379 this.data.addAll(r);
9380 this.totalLength = t;
9382 this.fireEvent("datachanged", this);
9384 this.totalLength = Math.max(t, this.data.length+r.length);
9387 this.fireEvent("load", this, r, options, o);
9388 if(options.callback){
9389 options.callback.call(options.scope || this, r, options, true);
9395 * Loads data from a passed data block. A Reader which understands the format of the data
9396 * must have been configured in the constructor.
9397 * @param {Object} data The data block from which to read the Records. The format of the data expected
9398 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9399 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9401 loadData : function(o, append){
9402 var r = this.reader.readRecords(o);
9403 this.loadRecords(r, {add: append}, true);
9407 * Gets the number of cached records.
9409 * <em>If using paging, this may not be the total size of the dataset. If the data object
9410 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9411 * the data set size</em>
9413 getCount : function(){
9414 return this.data.length || 0;
9418 * Gets the total number of records in the dataset as returned by the server.
9420 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9421 * the dataset size</em>
9423 getTotalCount : function(){
9424 return this.totalLength || 0;
9428 * Returns the sort state of the Store as an object with two properties:
9430 field {String} The name of the field by which the Records are sorted
9431 direction {String} The sort order, "ASC" or "DESC"
9434 getSortState : function(){
9435 return this.sortInfo;
9439 applySort : function(){
9440 if(this.sortInfo && !this.remoteSort){
9441 var s = this.sortInfo, f = s.field;
9442 var st = this.fields.get(f).sortType;
9443 var fn = function(r1, r2){
9444 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9445 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9447 this.data.sort(s.direction, fn);
9448 if(this.snapshot && this.snapshot != this.data){
9449 this.snapshot.sort(s.direction, fn);
9455 * Sets the default sort column and order to be used by the next load operation.
9456 * @param {String} fieldName The name of the field to sort by.
9457 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9459 setDefaultSort : function(field, dir){
9460 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9465 * If remote sorting is used, the sort is performed on the server, and the cache is
9466 * reloaded. If local sorting is used, the cache is sorted internally.
9467 * @param {String} fieldName The name of the field to sort by.
9468 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9470 sort : function(fieldName, dir){
9471 var f = this.fields.get(fieldName);
9473 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9475 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9476 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9481 this.sortToggle[f.name] = dir;
9482 this.sortInfo = {field: f.name, direction: dir};
9483 if(!this.remoteSort){
9485 this.fireEvent("datachanged", this);
9487 this.load(this.lastOptions);
9492 * Calls the specified function for each of the Records in the cache.
9493 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9494 * Returning <em>false</em> aborts and exits the iteration.
9495 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9497 each : function(fn, scope){
9498 this.data.each(fn, scope);
9502 * Gets all records modified since the last commit. Modified records are persisted across load operations
9503 * (e.g., during paging).
9504 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9506 getModifiedRecords : function(){
9507 return this.modified;
9511 createFilterFn : function(property, value, anyMatch){
9512 if(!value.exec){ // not a regex
9513 value = String(value);
9514 if(value.length == 0){
9517 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9520 return value.test(r.data[property]);
9525 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9526 * @param {String} property A field on your records
9527 * @param {Number} start The record index to start at (defaults to 0)
9528 * @param {Number} end The last record index to include (defaults to length - 1)
9529 * @return {Number} The sum
9531 sum : function(property, start, end){
9532 var rs = this.data.items, v = 0;
9534 end = (end || end === 0) ? end : rs.length-1;
9536 for(var i = start; i <= end; i++){
9537 v += (rs[i].data[property] || 0);
9543 * Filter the records by a specified property.
9544 * @param {String} field A field on your records
9545 * @param {String/RegExp} value Either a string that the field
9546 * should start with or a RegExp to test against the field
9547 * @param {Boolean} anyMatch True to match any part not just the beginning
9549 filter : function(property, value, anyMatch){
9550 var fn = this.createFilterFn(property, value, anyMatch);
9551 return fn ? this.filterBy(fn) : this.clearFilter();
9555 * Filter by a function. The specified function will be called with each
9556 * record in this data source. If the function returns true the record is included,
9557 * otherwise it is filtered.
9558 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9559 * @param {Object} scope (optional) The scope of the function (defaults to this)
9561 filterBy : function(fn, scope){
9562 this.snapshot = this.snapshot || this.data;
9563 this.data = this.queryBy(fn, scope||this);
9564 this.fireEvent("datachanged", this);
9568 * Query the records by a specified property.
9569 * @param {String} field A field on your records
9570 * @param {String/RegExp} value Either a string that the field
9571 * should start with or a RegExp to test against the field
9572 * @param {Boolean} anyMatch True to match any part not just the beginning
9573 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9575 query : function(property, value, anyMatch){
9576 var fn = this.createFilterFn(property, value, anyMatch);
9577 return fn ? this.queryBy(fn) : this.data.clone();
9581 * Query by a function. The specified function will be called with each
9582 * record in this data source. If the function returns true the record is included
9584 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9585 * @param {Object} scope (optional) The scope of the function (defaults to this)
9586 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9588 queryBy : function(fn, scope){
9589 var data = this.snapshot || this.data;
9590 return data.filterBy(fn, scope||this);
9594 * Collects unique values for a particular dataIndex from this store.
9595 * @param {String} dataIndex The property to collect
9596 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9597 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9598 * @return {Array} An array of the unique values
9600 collect : function(dataIndex, allowNull, bypassFilter){
9601 var d = (bypassFilter === true && this.snapshot) ?
9602 this.snapshot.items : this.data.items;
9603 var v, sv, r = [], l = {};
9604 for(var i = 0, len = d.length; i < len; i++){
9605 v = d[i].data[dataIndex];
9607 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9616 * Revert to a view of the Record cache with no filtering applied.
9617 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9619 clearFilter : function(suppressEvent){
9620 if(this.snapshot && this.snapshot != this.data){
9621 this.data = this.snapshot;
9622 delete this.snapshot;
9623 if(suppressEvent !== true){
9624 this.fireEvent("datachanged", this);
9630 afterEdit : function(record){
9631 if(this.modified.indexOf(record) == -1){
9632 this.modified.push(record);
9634 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9638 afterReject : function(record){
9639 this.modified.remove(record);
9640 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9644 afterCommit : function(record){
9645 this.modified.remove(record);
9646 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9650 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9651 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9653 commitChanges : function(){
9654 var m = this.modified.slice(0);
9656 for(var i = 0, len = m.length; i < len; i++){
9662 * Cancel outstanding changes on all changed records.
9664 rejectChanges : function(){
9665 var m = this.modified.slice(0);
9667 for(var i = 0, len = m.length; i < len; i++){
9672 onMetaChange : function(meta, rtype, o){
9673 this.recordType = rtype;
9674 this.fields = rtype.prototype.fields;
9675 delete this.snapshot;
9676 this.sortInfo = meta.sortInfo || this.sortInfo;
9678 this.fireEvent('metachange', this, this.reader.meta);
9681 moveIndex : function(data, type)
9683 var index = this.indexOf(data);
9685 var newIndex = index + type;
9689 this.insert(newIndex, data);
9694 * Ext JS Library 1.1.1
9695 * Copyright(c) 2006-2007, Ext JS, LLC.
9697 * Originally Released Under LGPL - original licence link has changed is not relivant.
9700 * <script type="text/javascript">
9704 * @class Roo.data.SimpleStore
9705 * @extends Roo.data.Store
9706 * Small helper class to make creating Stores from Array data easier.
9707 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9708 * @cfg {Array} fields An array of field definition objects, or field name strings.
9709 * @cfg {Array} data The multi-dimensional array of data
9711 * @param {Object} config
9713 Roo.data.SimpleStore = function(config){
9714 Roo.data.SimpleStore.superclass.constructor.call(this, {
9716 reader: new Roo.data.ArrayReader({
9719 Roo.data.Record.create(config.fields)
9721 proxy : new Roo.data.MemoryProxy(config.data)
9725 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9727 * Ext JS Library 1.1.1
9728 * Copyright(c) 2006-2007, Ext JS, LLC.
9730 * Originally Released Under LGPL - original licence link has changed is not relivant.
9733 * <script type="text/javascript">
9738 * @extends Roo.data.Store
9739 * @class Roo.data.JsonStore
9740 * Small helper class to make creating Stores for JSON data easier. <br/>
9742 var store = new Roo.data.JsonStore({
9743 url: 'get-images.php',
9745 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9748 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9749 * JsonReader and HttpProxy (unless inline data is provided).</b>
9750 * @cfg {Array} fields An array of field definition objects, or field name strings.
9752 * @param {Object} config
9754 Roo.data.JsonStore = function(c){
9755 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9756 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9757 reader: new Roo.data.JsonReader(c, c.fields)
9760 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9762 * Ext JS Library 1.1.1
9763 * Copyright(c) 2006-2007, Ext JS, LLC.
9765 * Originally Released Under LGPL - original licence link has changed is not relivant.
9768 * <script type="text/javascript">
9772 Roo.data.Field = function(config){
9773 if(typeof config == "string"){
9774 config = {name: config};
9776 Roo.apply(this, config);
9782 var st = Roo.data.SortTypes;
9783 // named sortTypes are supported, here we look them up
9784 if(typeof this.sortType == "string"){
9785 this.sortType = st[this.sortType];
9788 // set default sortType for strings and dates
9792 this.sortType = st.asUCString;
9795 this.sortType = st.asDate;
9798 this.sortType = st.none;
9803 var stripRe = /[\$,%]/g;
9805 // prebuilt conversion function for this field, instead of
9806 // switching every time we're reading a value
9808 var cv, dateFormat = this.dateFormat;
9813 cv = function(v){ return v; };
9816 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9820 return v !== undefined && v !== null && v !== '' ?
9821 parseInt(String(v).replace(stripRe, ""), 10) : '';
9826 return v !== undefined && v !== null && v !== '' ?
9827 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9832 cv = function(v){ return v === true || v === "true" || v == 1; };
9839 if(v instanceof Date){
9843 if(dateFormat == "timestamp"){
9844 return new Date(v*1000);
9846 return Date.parseDate(v, dateFormat);
9848 var parsed = Date.parse(v);
9849 return parsed ? new Date(parsed) : null;
9858 Roo.data.Field.prototype = {
9866 * Ext JS Library 1.1.1
9867 * Copyright(c) 2006-2007, Ext JS, LLC.
9869 * Originally Released Under LGPL - original licence link has changed is not relivant.
9872 * <script type="text/javascript">
9875 // Base class for reading structured data from a data source. This class is intended to be
9876 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9879 * @class Roo.data.DataReader
9880 * Base class for reading structured data from a data source. This class is intended to be
9881 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9884 Roo.data.DataReader = function(meta, recordType){
9888 this.recordType = recordType instanceof Array ?
9889 Roo.data.Record.create(recordType) : recordType;
9892 Roo.data.DataReader.prototype = {
9894 * Create an empty record
9895 * @param {Object} data (optional) - overlay some values
9896 * @return {Roo.data.Record} record created.
9898 newRow : function(d) {
9900 this.recordType.prototype.fields.each(function(c) {
9902 case 'int' : da[c.name] = 0; break;
9903 case 'date' : da[c.name] = new Date(); break;
9904 case 'float' : da[c.name] = 0.0; break;
9905 case 'boolean' : da[c.name] = false; break;
9906 default : da[c.name] = ""; break;
9910 return new this.recordType(Roo.apply(da, d));
9915 * Ext JS Library 1.1.1
9916 * Copyright(c) 2006-2007, Ext JS, LLC.
9918 * Originally Released Under LGPL - original licence link has changed is not relivant.
9921 * <script type="text/javascript">
9925 * @class Roo.data.DataProxy
9926 * @extends Roo.data.Observable
9927 * This class is an abstract base class for implementations which provide retrieval of
9928 * unformatted data objects.<br>
9930 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9931 * (of the appropriate type which knows how to parse the data object) to provide a block of
9932 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9934 * Custom implementations must implement the load method as described in
9935 * {@link Roo.data.HttpProxy#load}.
9937 Roo.data.DataProxy = function(){
9941 * Fires before a network request is made to retrieve a data object.
9942 * @param {Object} This DataProxy object.
9943 * @param {Object} params The params parameter to the load function.
9948 * Fires before the load method's callback is called.
9949 * @param {Object} This DataProxy object.
9950 * @param {Object} o The data object.
9951 * @param {Object} arg The callback argument object passed to the load function.
9955 * @event loadexception
9956 * Fires if an Exception occurs during data retrieval.
9957 * @param {Object} This DataProxy object.
9958 * @param {Object} o The data object.
9959 * @param {Object} arg The callback argument object passed to the load function.
9960 * @param {Object} e The Exception.
9962 loadexception : true
9964 Roo.data.DataProxy.superclass.constructor.call(this);
9967 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9970 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9974 * Ext JS Library 1.1.1
9975 * Copyright(c) 2006-2007, Ext JS, LLC.
9977 * Originally Released Under LGPL - original licence link has changed is not relivant.
9980 * <script type="text/javascript">
9983 * @class Roo.data.MemoryProxy
9984 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9985 * to the Reader when its load method is called.
9987 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9989 Roo.data.MemoryProxy = function(data){
9993 Roo.data.MemoryProxy.superclass.constructor.call(this);
9997 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9999 * Load data from the requested source (in this case an in-memory
10000 * data object passed to the constructor), read the data object into
10001 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10002 * process that block using the passed callback.
10003 * @param {Object} params This parameter is not used by the MemoryProxy class.
10004 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10005 * object into a block of Roo.data.Records.
10006 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10007 * The function must be passed <ul>
10008 * <li>The Record block object</li>
10009 * <li>The "arg" argument from the load function</li>
10010 * <li>A boolean success indicator</li>
10012 * @param {Object} scope The scope in which to call the callback
10013 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10015 load : function(params, reader, callback, scope, arg){
10016 params = params || {};
10019 result = reader.readRecords(this.data);
10021 this.fireEvent("loadexception", this, arg, null, e);
10022 callback.call(scope, null, arg, false);
10025 callback.call(scope, result, arg, true);
10029 update : function(params, records){
10034 * Ext JS Library 1.1.1
10035 * Copyright(c) 2006-2007, Ext JS, LLC.
10037 * Originally Released Under LGPL - original licence link has changed is not relivant.
10040 * <script type="text/javascript">
10043 * @class Roo.data.HttpProxy
10044 * @extends Roo.data.DataProxy
10045 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10046 * configured to reference a certain URL.<br><br>
10048 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10049 * from which the running page was served.<br><br>
10051 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10053 * Be aware that to enable the browser to parse an XML document, the server must set
10054 * the Content-Type header in the HTTP response to "text/xml".
10056 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10057 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10058 * will be used to make the request.
10060 Roo.data.HttpProxy = function(conn){
10061 Roo.data.HttpProxy.superclass.constructor.call(this);
10062 // is conn a conn config or a real conn?
10064 this.useAjax = !conn || !conn.events;
10068 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10069 // thse are take from connection...
10072 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10075 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10076 * extra parameters to each request made by this object. (defaults to undefined)
10079 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10080 * to each request made by this object. (defaults to undefined)
10083 * @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)
10086 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10089 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10095 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10099 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10100 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10101 * a finer-grained basis than the DataProxy events.
10103 getConnection : function(){
10104 return this.useAjax ? Roo.Ajax : this.conn;
10108 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10109 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10110 * process that block using the passed callback.
10111 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10112 * for the request to the remote server.
10113 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10114 * object into a block of Roo.data.Records.
10115 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10116 * The function must be passed <ul>
10117 * <li>The Record block object</li>
10118 * <li>The "arg" argument from the load function</li>
10119 * <li>A boolean success indicator</li>
10121 * @param {Object} scope The scope in which to call the callback
10122 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10124 load : function(params, reader, callback, scope, arg){
10125 if(this.fireEvent("beforeload", this, params) !== false){
10127 params : params || {},
10129 callback : callback,
10134 callback : this.loadResponse,
10138 Roo.applyIf(o, this.conn);
10139 if(this.activeRequest){
10140 Roo.Ajax.abort(this.activeRequest);
10142 this.activeRequest = Roo.Ajax.request(o);
10144 this.conn.request(o);
10147 callback.call(scope||this, null, arg, false);
10152 loadResponse : function(o, success, response){
10153 delete this.activeRequest;
10155 this.fireEvent("loadexception", this, o, response);
10156 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10161 result = o.reader.read(response);
10163 this.fireEvent("loadexception", this, o, response, e);
10164 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10168 this.fireEvent("load", this, o, o.request.arg);
10169 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10173 update : function(dataSet){
10178 updateResponse : function(dataSet){
10183 * Ext JS Library 1.1.1
10184 * Copyright(c) 2006-2007, Ext JS, LLC.
10186 * Originally Released Under LGPL - original licence link has changed is not relivant.
10189 * <script type="text/javascript">
10193 * @class Roo.data.ScriptTagProxy
10194 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10195 * other than the originating domain of the running page.<br><br>
10197 * <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
10198 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10200 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10201 * source code that is used as the source inside a <script> tag.<br><br>
10203 * In order for the browser to process the returned data, the server must wrap the data object
10204 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10205 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10206 * depending on whether the callback name was passed:
10209 boolean scriptTag = false;
10210 String cb = request.getParameter("callback");
10213 response.setContentType("text/javascript");
10215 response.setContentType("application/x-json");
10217 Writer out = response.getWriter();
10219 out.write(cb + "(");
10221 out.print(dataBlock.toJsonString());
10228 * @param {Object} config A configuration object.
10230 Roo.data.ScriptTagProxy = function(config){
10231 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10232 Roo.apply(this, config);
10233 this.head = document.getElementsByTagName("head")[0];
10236 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10238 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10240 * @cfg {String} url The URL from which to request the data object.
10243 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10247 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10248 * the server the name of the callback function set up by the load call to process the returned data object.
10249 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10250 * javascript output which calls this named function passing the data object as its only parameter.
10252 callbackParam : "callback",
10254 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10255 * name to the request.
10260 * Load data from the configured URL, read the data object into
10261 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10262 * process that block using the passed callback.
10263 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10264 * for the request to the remote server.
10265 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10266 * object into a block of Roo.data.Records.
10267 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10268 * The function must be passed <ul>
10269 * <li>The Record block object</li>
10270 * <li>The "arg" argument from the load function</li>
10271 * <li>A boolean success indicator</li>
10273 * @param {Object} scope The scope in which to call the callback
10274 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10276 load : function(params, reader, callback, scope, arg){
10277 if(this.fireEvent("beforeload", this, params) !== false){
10279 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10281 var url = this.url;
10282 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10284 url += "&_dc=" + (new Date().getTime());
10286 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10289 cb : "stcCallback"+transId,
10290 scriptId : "stcScript"+transId,
10294 callback : callback,
10300 window[trans.cb] = function(o){
10301 conn.handleResponse(o, trans);
10304 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10306 if(this.autoAbort !== false){
10310 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10312 var script = document.createElement("script");
10313 script.setAttribute("src", url);
10314 script.setAttribute("type", "text/javascript");
10315 script.setAttribute("id", trans.scriptId);
10316 this.head.appendChild(script);
10318 this.trans = trans;
10320 callback.call(scope||this, null, arg, false);
10325 isLoading : function(){
10326 return this.trans ? true : false;
10330 * Abort the current server request.
10332 abort : function(){
10333 if(this.isLoading()){
10334 this.destroyTrans(this.trans);
10339 destroyTrans : function(trans, isLoaded){
10340 this.head.removeChild(document.getElementById(trans.scriptId));
10341 clearTimeout(trans.timeoutId);
10343 window[trans.cb] = undefined;
10345 delete window[trans.cb];
10348 // if hasn't been loaded, wait for load to remove it to prevent script error
10349 window[trans.cb] = function(){
10350 window[trans.cb] = undefined;
10352 delete window[trans.cb];
10359 handleResponse : function(o, trans){
10360 this.trans = false;
10361 this.destroyTrans(trans, true);
10364 result = trans.reader.readRecords(o);
10366 this.fireEvent("loadexception", this, o, trans.arg, e);
10367 trans.callback.call(trans.scope||window, null, trans.arg, false);
10370 this.fireEvent("load", this, o, trans.arg);
10371 trans.callback.call(trans.scope||window, result, trans.arg, true);
10375 handleFailure : function(trans){
10376 this.trans = false;
10377 this.destroyTrans(trans, false);
10378 this.fireEvent("loadexception", this, null, trans.arg);
10379 trans.callback.call(trans.scope||window, null, trans.arg, false);
10383 * Ext JS Library 1.1.1
10384 * Copyright(c) 2006-2007, Ext JS, LLC.
10386 * Originally Released Under LGPL - original licence link has changed is not relivant.
10389 * <script type="text/javascript">
10393 * @class Roo.data.JsonReader
10394 * @extends Roo.data.DataReader
10395 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10396 * based on mappings in a provided Roo.data.Record constructor.
10398 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10399 * in the reply previously.
10404 var RecordDef = Roo.data.Record.create([
10405 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10406 {name: 'occupation'} // This field will use "occupation" as the mapping.
10408 var myReader = new Roo.data.JsonReader({
10409 totalProperty: "results", // The property which contains the total dataset size (optional)
10410 root: "rows", // The property which contains an Array of row objects
10411 id: "id" // The property within each row object that provides an ID for the record (optional)
10415 * This would consume a JSON file like this:
10417 { 'results': 2, 'rows': [
10418 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10419 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10422 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10423 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10424 * paged from the remote server.
10425 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10426 * @cfg {String} root name of the property which contains the Array of row objects.
10427 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10429 * Create a new JsonReader
10430 * @param {Object} meta Metadata configuration options
10431 * @param {Object} recordType Either an Array of field definition objects,
10432 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10434 Roo.data.JsonReader = function(meta, recordType){
10437 // set some defaults:
10438 Roo.applyIf(meta, {
10439 totalProperty: 'total',
10440 successProperty : 'success',
10445 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10447 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10450 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10451 * Used by Store query builder to append _requestMeta to params.
10454 metaFromRemote : false,
10456 * This method is only used by a DataProxy which has retrieved data from a remote server.
10457 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10458 * @return {Object} data A data block which is used by an Roo.data.Store object as
10459 * a cache of Roo.data.Records.
10461 read : function(response){
10462 var json = response.responseText;
10464 var o = /* eval:var:o */ eval("("+json+")");
10466 throw {message: "JsonReader.read: Json object not found"};
10472 this.metaFromRemote = true;
10473 this.meta = o.metaData;
10474 this.recordType = Roo.data.Record.create(o.metaData.fields);
10475 this.onMetaChange(this.meta, this.recordType, o);
10477 return this.readRecords(o);
10480 // private function a store will implement
10481 onMetaChange : function(meta, recordType, o){
10488 simpleAccess: function(obj, subsc) {
10495 getJsonAccessor: function(){
10497 return function(expr) {
10499 return(re.test(expr))
10500 ? new Function("obj", "return obj." + expr)
10505 return Roo.emptyFn;
10510 * Create a data block containing Roo.data.Records from an XML document.
10511 * @param {Object} o An object which contains an Array of row objects in the property specified
10512 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10513 * which contains the total size of the dataset.
10514 * @return {Object} data A data block which is used by an Roo.data.Store object as
10515 * a cache of Roo.data.Records.
10517 readRecords : function(o){
10519 * After any data loads, the raw JSON data is available for further custom processing.
10523 var s = this.meta, Record = this.recordType,
10524 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10526 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10528 if(s.totalProperty) {
10529 this.getTotal = this.getJsonAccessor(s.totalProperty);
10531 if(s.successProperty) {
10532 this.getSuccess = this.getJsonAccessor(s.successProperty);
10534 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10536 var g = this.getJsonAccessor(s.id);
10537 this.getId = function(rec) {
10539 return (r === undefined || r === "") ? null : r;
10542 this.getId = function(){return null;};
10545 for(var jj = 0; jj < fl; jj++){
10547 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10548 this.ef[jj] = this.getJsonAccessor(map);
10552 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10553 if(s.totalProperty){
10554 var vt = parseInt(this.getTotal(o), 10);
10559 if(s.successProperty){
10560 var vs = this.getSuccess(o);
10561 if(vs === false || vs === 'false'){
10566 for(var i = 0; i < c; i++){
10569 var id = this.getId(n);
10570 for(var j = 0; j < fl; j++){
10572 var v = this.ef[j](n);
10574 Roo.log('missing convert for ' + f.name);
10578 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10580 var record = new Record(values, id);
10582 records[i] = record;
10588 totalRecords : totalRecords
10593 * Ext JS Library 1.1.1
10594 * Copyright(c) 2006-2007, Ext JS, LLC.
10596 * Originally Released Under LGPL - original licence link has changed is not relivant.
10599 * <script type="text/javascript">
10603 * @class Roo.data.ArrayReader
10604 * @extends Roo.data.DataReader
10605 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10606 * Each element of that Array represents a row of data fields. The
10607 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10608 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10612 var RecordDef = Roo.data.Record.create([
10613 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10614 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10616 var myReader = new Roo.data.ArrayReader({
10617 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10621 * This would consume an Array like this:
10623 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10625 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10627 * Create a new JsonReader
10628 * @param {Object} meta Metadata configuration options.
10629 * @param {Object} recordType Either an Array of field definition objects
10630 * as specified to {@link Roo.data.Record#create},
10631 * or an {@link Roo.data.Record} object
10632 * created using {@link Roo.data.Record#create}.
10634 Roo.data.ArrayReader = function(meta, recordType){
10635 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10638 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10640 * Create a data block containing Roo.data.Records from an XML document.
10641 * @param {Object} o An Array of row objects which represents the dataset.
10642 * @return {Object} data A data block which is used by an Roo.data.Store object as
10643 * a cache of Roo.data.Records.
10645 readRecords : function(o){
10646 var sid = this.meta ? this.meta.id : null;
10647 var recordType = this.recordType, fields = recordType.prototype.fields;
10650 for(var i = 0; i < root.length; i++){
10653 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10654 for(var j = 0, jlen = fields.length; j < jlen; j++){
10655 var f = fields.items[j];
10656 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10657 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10659 values[f.name] = v;
10661 var record = new recordType(values, id);
10663 records[records.length] = record;
10667 totalRecords : records.length
10676 * @class Roo.bootstrap.ComboBox
10677 * @extends Roo.bootstrap.TriggerField
10678 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10679 * @cfg {Boolean} append (true|false) default false
10680 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10681 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10682 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10683 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10684 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10686 * Create a new ComboBox.
10687 * @param {Object} config Configuration options
10689 Roo.bootstrap.ComboBox = function(config){
10690 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10694 * Fires when the dropdown list is expanded
10695 * @param {Roo.bootstrap.ComboBox} combo This combo box
10700 * Fires when the dropdown list is collapsed
10701 * @param {Roo.bootstrap.ComboBox} combo This combo box
10705 * @event beforeselect
10706 * Fires before a list item is selected. Return false to cancel the selection.
10707 * @param {Roo.bootstrap.ComboBox} combo This combo box
10708 * @param {Roo.data.Record} record The data record returned from the underlying store
10709 * @param {Number} index The index of the selected item in the dropdown list
10711 'beforeselect' : true,
10714 * Fires when a list item is selected
10715 * @param {Roo.bootstrap.ComboBox} combo This combo box
10716 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10717 * @param {Number} index The index of the selected item in the dropdown list
10721 * @event beforequery
10722 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10723 * The event object passed has these properties:
10724 * @param {Roo.bootstrap.ComboBox} combo This combo box
10725 * @param {String} query The query
10726 * @param {Boolean} forceAll true to force "all" query
10727 * @param {Boolean} cancel true to cancel the query
10728 * @param {Object} e The query event object
10730 'beforequery': true,
10733 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10734 * @param {Roo.bootstrap.ComboBox} combo This combo box
10739 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10740 * @param {Roo.bootstrap.ComboBox} combo This combo box
10741 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10746 * Fires when the remove value from the combobox array
10747 * @param {Roo.bootstrap.ComboBox} combo This combo box
10754 this.tickItems = [];
10756 this.selectedIndex = -1;
10757 if(this.mode == 'local'){
10758 if(config.queryDelay === undefined){
10759 this.queryDelay = 10;
10761 if(config.minChars === undefined){
10767 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10770 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10771 * rendering into an Roo.Editor, defaults to false)
10774 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10775 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10778 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10781 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10782 * the dropdown list (defaults to undefined, with no header element)
10786 * @cfg {String/Roo.Template} tpl The template to use to render the output
10790 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10792 listWidth: undefined,
10794 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10795 * mode = 'remote' or 'text' if mode = 'local')
10797 displayField: undefined,
10799 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10800 * mode = 'remote' or 'value' if mode = 'local').
10801 * Note: use of a valueField requires the user make a selection
10802 * in order for a value to be mapped.
10804 valueField: undefined,
10808 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10809 * field's data value (defaults to the underlying DOM element's name)
10811 hiddenName: undefined,
10813 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10817 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10819 selectedClass: 'active',
10822 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10826 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10827 * anchor positions (defaults to 'tl-bl')
10829 listAlign: 'tl-bl?',
10831 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10835 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10836 * query specified by the allQuery config option (defaults to 'query')
10838 triggerAction: 'query',
10840 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10841 * (defaults to 4, does not apply if editable = false)
10845 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10846 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10850 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10851 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10855 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10856 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10860 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10861 * when editable = true (defaults to false)
10863 selectOnFocus:false,
10865 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10867 queryParam: 'query',
10869 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10870 * when mode = 'remote' (defaults to 'Loading...')
10872 loadingText: 'Loading...',
10874 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10878 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10882 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10883 * traditional select (defaults to true)
10887 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10891 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10895 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10896 * listWidth has a higher value)
10900 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10901 * allow the user to set arbitrary text into the field (defaults to false)
10903 forceSelection:false,
10905 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10906 * if typeAhead = true (defaults to 250)
10908 typeAheadDelay : 250,
10910 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10911 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10913 valueNotFoundText : undefined,
10915 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10917 blockFocus : false,
10920 * @cfg {Boolean} disableClear Disable showing of clear button.
10922 disableClear : false,
10924 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10926 alwaysQuery : false,
10929 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10934 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10936 invalidClass : "has-warning",
10939 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10941 validClass : "has-success",
10953 btnPosition : 'right',
10954 triggerList : true,
10955 showToggleBtn : true,
10956 // element that contains real text value.. (when hidden is used..)
10958 getAutoCreate : function()
10965 if(!this.tickable){
10966 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10971 * ComboBox with tickable selections
10974 var align = this.labelAlign || this.parentLabelAlign();
10977 cls : 'form-group roo-combobox-tickable' //input-group
10982 cls : 'tickable-buttons',
10987 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10994 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11001 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11008 buttons.cn.unshift({
11010 cls: 'select2-search-field-input'
11016 Roo.each(buttons.cn, function(c){
11018 c.cls += ' btn-' + _this.size;
11021 if (_this.disabled) {
11032 cls: 'form-hidden-field'
11036 cls: 'select2-choices',
11040 cls: 'select2-search-field',
11052 cls: 'select2-container input-group select2-container-multi',
11057 // cls: 'typeahead typeahead-long dropdown-menu',
11058 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11063 if(this.hasFeedback && !this.allowBlank){
11067 cls: 'glyphicon form-control-feedback'
11070 combobox.cn.push(feedback);
11073 if (align ==='left' && this.fieldLabel.length) {
11075 Roo.log("left and has label");
11081 cls : 'control-label col-sm-' + this.labelWidth,
11082 html : this.fieldLabel
11086 cls : "col-sm-" + (12 - this.labelWidth),
11093 } else if ( this.fieldLabel.length) {
11099 //cls : 'input-group-addon',
11100 html : this.fieldLabel
11110 Roo.log(" no label && no align");
11117 ['xs','sm','md','lg'].map(function(size){
11118 if (settings[size]) {
11119 cfg.cls += ' col-' + size + '-' + settings[size];
11128 initEvents: function()
11132 throw "can not find store for combo";
11134 this.store = Roo.factory(this.store, Roo.data);
11137 this.initTickableEvents();
11141 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11143 if(this.hiddenName){
11145 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11147 this.hiddenField.dom.value =
11148 this.hiddenValue !== undefined ? this.hiddenValue :
11149 this.value !== undefined ? this.value : '';
11151 // prevent input submission
11152 this.el.dom.removeAttribute('name');
11153 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11158 // this.el.dom.setAttribute('autocomplete', 'off');
11161 var cls = 'x-combo-list';
11163 //this.list = new Roo.Layer({
11164 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11170 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11171 _this.list.setWidth(lw);
11174 this.list.on('mouseover', this.onViewOver, this);
11175 this.list.on('mousemove', this.onViewMove, this);
11177 this.list.on('scroll', this.onViewScroll, this);
11180 this.list.swallowEvent('mousewheel');
11181 this.assetHeight = 0;
11184 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11185 this.assetHeight += this.header.getHeight();
11188 this.innerList = this.list.createChild({cls:cls+'-inner'});
11189 this.innerList.on('mouseover', this.onViewOver, this);
11190 this.innerList.on('mousemove', this.onViewMove, this);
11191 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11193 if(this.allowBlank && !this.pageSize && !this.disableClear){
11194 this.footer = this.list.createChild({cls:cls+'-ft'});
11195 this.pageTb = new Roo.Toolbar(this.footer);
11199 this.footer = this.list.createChild({cls:cls+'-ft'});
11200 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11201 {pageSize: this.pageSize});
11205 if (this.pageTb && this.allowBlank && !this.disableClear) {
11207 this.pageTb.add(new Roo.Toolbar.Fill(), {
11208 cls: 'x-btn-icon x-btn-clear',
11210 handler: function()
11213 _this.clearValue();
11214 _this.onSelect(false, -1);
11219 this.assetHeight += this.footer.getHeight();
11224 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11227 this.view = new Roo.View(this.list, this.tpl, {
11228 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11230 //this.view.wrapEl.setDisplayed(false);
11231 this.view.on('click', this.onViewClick, this);
11235 this.store.on('beforeload', this.onBeforeLoad, this);
11236 this.store.on('load', this.onLoad, this);
11237 this.store.on('loadexception', this.onLoadException, this);
11239 if(this.resizable){
11240 this.resizer = new Roo.Resizable(this.list, {
11241 pinned:true, handles:'se'
11243 this.resizer.on('resize', function(r, w, h){
11244 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11245 this.listWidth = w;
11246 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11247 this.restrictHeight();
11249 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11252 if(!this.editable){
11253 this.editable = true;
11254 this.setEditable(false);
11259 if (typeof(this.events.add.listeners) != 'undefined') {
11261 this.addicon = this.wrap.createChild(
11262 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11264 this.addicon.on('click', function(e) {
11265 this.fireEvent('add', this);
11268 if (typeof(this.events.edit.listeners) != 'undefined') {
11270 this.editicon = this.wrap.createChild(
11271 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11272 if (this.addicon) {
11273 this.editicon.setStyle('margin-left', '40px');
11275 this.editicon.on('click', function(e) {
11277 // we fire even if inothing is selected..
11278 this.fireEvent('edit', this, this.lastData );
11284 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11285 "up" : function(e){
11286 this.inKeyMode = true;
11290 "down" : function(e){
11291 if(!this.isExpanded()){
11292 this.onTriggerClick();
11294 this.inKeyMode = true;
11299 "enter" : function(e){
11300 // this.onViewClick();
11304 if(this.fireEvent("specialkey", this, e)){
11305 this.onViewClick(false);
11311 "esc" : function(e){
11315 "tab" : function(e){
11318 if(this.fireEvent("specialkey", this, e)){
11319 this.onViewClick(false);
11327 doRelay : function(foo, bar, hname){
11328 if(hname == 'down' || this.scope.isExpanded()){
11329 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11338 this.queryDelay = Math.max(this.queryDelay || 10,
11339 this.mode == 'local' ? 10 : 250);
11342 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11344 if(this.typeAhead){
11345 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11347 if(this.editable !== false){
11348 this.inputEl().on("keyup", this.onKeyUp, this);
11350 if(this.forceSelection){
11351 this.inputEl().on('blur', this.doForce, this);
11355 this.choices = this.el.select('ul.select2-choices', true).first();
11356 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11360 initTickableEvents: function()
11364 if(this.hiddenName){
11366 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11368 this.hiddenField.dom.value =
11369 this.hiddenValue !== undefined ? this.hiddenValue :
11370 this.value !== undefined ? this.value : '';
11372 // prevent input submission
11373 this.el.dom.removeAttribute('name');
11374 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11379 // this.list = this.el.select('ul.dropdown-menu',true).first();
11381 this.choices = this.el.select('ul.select2-choices', true).first();
11382 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11383 if(this.triggerList){
11384 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11387 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11388 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11390 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11391 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11393 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11394 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11396 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11397 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11398 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11401 this.cancelBtn.hide();
11406 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11407 _this.list.setWidth(lw);
11410 this.list.on('mouseover', this.onViewOver, this);
11411 this.list.on('mousemove', this.onViewMove, this);
11413 this.list.on('scroll', this.onViewScroll, this);
11416 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>';
11419 this.view = new Roo.View(this.list, this.tpl, {
11420 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11423 //this.view.wrapEl.setDisplayed(false);
11424 this.view.on('click', this.onViewClick, this);
11428 this.store.on('beforeload', this.onBeforeLoad, this);
11429 this.store.on('load', this.onLoad, this);
11430 this.store.on('loadexception', this.onLoadException, this);
11433 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11434 "up" : function(e){
11435 this.inKeyMode = true;
11439 "down" : function(e){
11440 this.inKeyMode = true;
11444 "enter" : function(e){
11445 if(this.fireEvent("specialkey", this, e)){
11446 this.onViewClick(false);
11452 "esc" : function(e){
11453 this.onTickableFooterButtonClick(e, false, false);
11456 "tab" : function(e){
11457 this.fireEvent("specialkey", this, e);
11459 this.onTickableFooterButtonClick(e, false, false);
11466 doRelay : function(e, fn, key){
11467 if(this.scope.isExpanded()){
11468 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11477 this.queryDelay = Math.max(this.queryDelay || 10,
11478 this.mode == 'local' ? 10 : 250);
11481 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11483 if(this.typeAhead){
11484 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11487 if(this.editable !== false){
11488 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11493 onDestroy : function(){
11495 this.view.setStore(null);
11496 this.view.el.removeAllListeners();
11497 this.view.el.remove();
11498 this.view.purgeListeners();
11501 this.list.dom.innerHTML = '';
11505 this.store.un('beforeload', this.onBeforeLoad, this);
11506 this.store.un('load', this.onLoad, this);
11507 this.store.un('loadexception', this.onLoadException, this);
11509 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11513 fireKey : function(e){
11514 if(e.isNavKeyPress() && !this.list.isVisible()){
11515 this.fireEvent("specialkey", this, e);
11520 onResize: function(w, h){
11521 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11523 // if(typeof w != 'number'){
11524 // // we do not handle it!?!?
11527 // var tw = this.trigger.getWidth();
11528 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11529 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11531 // this.inputEl().setWidth( this.adjustWidth('input', x));
11533 // //this.trigger.setStyle('left', x+'px');
11535 // if(this.list && this.listWidth === undefined){
11536 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11537 // this.list.setWidth(lw);
11538 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11546 * Allow or prevent the user from directly editing the field text. If false is passed,
11547 * the user will only be able to select from the items defined in the dropdown list. This method
11548 * is the runtime equivalent of setting the 'editable' config option at config time.
11549 * @param {Boolean} value True to allow the user to directly edit the field text
11551 setEditable : function(value){
11552 if(value == this.editable){
11555 this.editable = value;
11557 this.inputEl().dom.setAttribute('readOnly', true);
11558 this.inputEl().on('mousedown', this.onTriggerClick, this);
11559 this.inputEl().addClass('x-combo-noedit');
11561 this.inputEl().dom.setAttribute('readOnly', false);
11562 this.inputEl().un('mousedown', this.onTriggerClick, this);
11563 this.inputEl().removeClass('x-combo-noedit');
11569 onBeforeLoad : function(combo,opts){
11570 if(!this.hasFocus){
11574 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11576 this.restrictHeight();
11577 this.selectedIndex = -1;
11581 onLoad : function(){
11583 this.hasQuery = false;
11585 if(!this.hasFocus){
11589 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11590 this.loading.hide();
11593 if(this.store.getCount() > 0){
11595 this.restrictHeight();
11596 if(this.lastQuery == this.allQuery){
11597 if(this.editable && !this.tickable){
11598 this.inputEl().dom.select();
11602 !this.selectByValue(this.value, true) &&
11605 !this.store.lastOptions ||
11606 typeof(this.store.lastOptions.add) == 'undefined' ||
11607 this.store.lastOptions.add != true
11610 this.select(0, true);
11613 if(this.autoFocus){
11616 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11617 this.taTask.delay(this.typeAheadDelay);
11621 this.onEmptyResults();
11627 onLoadException : function()
11629 this.hasQuery = false;
11631 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11632 this.loading.hide();
11635 if(this.tickable && this.editable){
11641 Roo.log(this.store.reader.jsonData);
11642 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11644 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11650 onTypeAhead : function(){
11651 if(this.store.getCount() > 0){
11652 var r = this.store.getAt(0);
11653 var newValue = r.data[this.displayField];
11654 var len = newValue.length;
11655 var selStart = this.getRawValue().length;
11657 if(selStart != len){
11658 this.setRawValue(newValue);
11659 this.selectText(selStart, newValue.length);
11665 onSelect : function(record, index){
11667 if(this.fireEvent('beforeselect', this, record, index) !== false){
11669 this.setFromData(index > -1 ? record.data : false);
11672 this.fireEvent('select', this, record, index);
11677 * Returns the currently selected field value or empty string if no value is set.
11678 * @return {String} value The selected value
11680 getValue : function(){
11683 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11686 if(this.valueField){
11687 return typeof this.value != 'undefined' ? this.value : '';
11689 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11694 * Clears any text/value currently set in the field
11696 clearValue : function(){
11697 if(this.hiddenField){
11698 this.hiddenField.dom.value = '';
11701 this.setRawValue('');
11702 this.lastSelectionText = '';
11703 this.lastData = false;
11708 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11709 * will be displayed in the field. If the value does not match the data value of an existing item,
11710 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11711 * Otherwise the field will be blank (although the value will still be set).
11712 * @param {String} value The value to match
11714 setValue : function(v){
11721 if(this.valueField){
11722 var r = this.findRecord(this.valueField, v);
11724 text = r.data[this.displayField];
11725 }else if(this.valueNotFoundText !== undefined){
11726 text = this.valueNotFoundText;
11729 this.lastSelectionText = text;
11730 if(this.hiddenField){
11731 this.hiddenField.dom.value = v;
11733 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11737 * @property {Object} the last set data for the element
11742 * Sets the value of the field based on a object which is related to the record format for the store.
11743 * @param {Object} value the value to set as. or false on reset?
11745 setFromData : function(o){
11752 var dv = ''; // display value
11753 var vv = ''; // value value..
11755 if (this.displayField) {
11756 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11758 // this is an error condition!!!
11759 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11762 if(this.valueField){
11763 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11766 if(this.hiddenField){
11767 this.hiddenField.dom.value = vv;
11769 this.lastSelectionText = dv;
11770 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11774 // no hidden field.. - we store the value in 'value', but still display
11775 // display field!!!!
11776 this.lastSelectionText = dv;
11777 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11783 reset : function(){
11784 // overridden so that last data is reset..
11785 this.setValue(this.originalValue);
11786 this.clearInvalid();
11787 this.lastData = false;
11789 this.view.clearSelections();
11793 findRecord : function(prop, value){
11795 if(this.store.getCount() > 0){
11796 this.store.each(function(r){
11797 if(r.data[prop] == value){
11807 getName: function()
11809 // returns hidden if it's set..
11810 if (!this.rendered) {return ''};
11811 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11815 onViewMove : function(e, t){
11816 this.inKeyMode = false;
11820 onViewOver : function(e, t){
11821 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11824 var item = this.view.findItemFromChild(t);
11827 var index = this.view.indexOf(item);
11828 this.select(index, false);
11833 onViewClick : function(view, doFocus, el, e)
11835 var index = this.view.getSelectedIndexes()[0];
11837 var r = this.store.getAt(index);
11841 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11848 Roo.each(this.tickItems, function(v,k){
11850 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11851 _this.tickItems.splice(k, 1);
11853 if(typeof(e) == 'undefined' && view == false){
11854 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11866 this.tickItems.push(r.data);
11868 if(typeof(e) == 'undefined' && view == false){
11869 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11876 this.onSelect(r, index);
11878 if(doFocus !== false && !this.blockFocus){
11879 this.inputEl().focus();
11884 restrictHeight : function(){
11885 //this.innerList.dom.style.height = '';
11886 //var inner = this.innerList.dom;
11887 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11888 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11889 //this.list.beginUpdate();
11890 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11891 this.list.alignTo(this.inputEl(), this.listAlign);
11892 this.list.alignTo(this.inputEl(), this.listAlign);
11893 //this.list.endUpdate();
11897 onEmptyResults : function(){
11899 if(this.tickable && this.editable){
11900 this.restrictHeight();
11908 * Returns true if the dropdown list is expanded, else false.
11910 isExpanded : function(){
11911 return this.list.isVisible();
11915 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11916 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11917 * @param {String} value The data value of the item to select
11918 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11919 * selected item if it is not currently in view (defaults to true)
11920 * @return {Boolean} True if the value matched an item in the list, else false
11922 selectByValue : function(v, scrollIntoView){
11923 if(v !== undefined && v !== null){
11924 var r = this.findRecord(this.valueField || this.displayField, v);
11926 this.select(this.store.indexOf(r), scrollIntoView);
11934 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11935 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11936 * @param {Number} index The zero-based index of the list item to select
11937 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11938 * selected item if it is not currently in view (defaults to true)
11940 select : function(index, scrollIntoView){
11941 this.selectedIndex = index;
11942 this.view.select(index);
11943 if(scrollIntoView !== false){
11944 var el = this.view.getNode(index);
11946 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11949 this.list.scrollChildIntoView(el, false);
11955 selectNext : function(){
11956 var ct = this.store.getCount();
11958 if(this.selectedIndex == -1){
11960 }else if(this.selectedIndex < ct-1){
11961 this.select(this.selectedIndex+1);
11967 selectPrev : function(){
11968 var ct = this.store.getCount();
11970 if(this.selectedIndex == -1){
11972 }else if(this.selectedIndex != 0){
11973 this.select(this.selectedIndex-1);
11979 onKeyUp : function(e){
11980 if(this.editable !== false && !e.isSpecialKey()){
11981 this.lastKey = e.getKey();
11982 this.dqTask.delay(this.queryDelay);
11987 validateBlur : function(){
11988 return !this.list || !this.list.isVisible();
11992 initQuery : function(){
11994 var v = this.getRawValue();
11996 if(this.tickable && this.editable){
11997 v = this.tickableInputEl().getValue();
12004 doForce : function(){
12005 if(this.inputEl().dom.value.length > 0){
12006 this.inputEl().dom.value =
12007 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12013 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12014 * query allowing the query action to be canceled if needed.
12015 * @param {String} query The SQL query to execute
12016 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12017 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12018 * saved in the current store (defaults to false)
12020 doQuery : function(q, forceAll){
12022 if(q === undefined || q === null){
12027 forceAll: forceAll,
12031 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12036 forceAll = qe.forceAll;
12037 if(forceAll === true || (q.length >= this.minChars)){
12039 this.hasQuery = true;
12041 if(this.lastQuery != q || this.alwaysQuery){
12042 this.lastQuery = q;
12043 if(this.mode == 'local'){
12044 this.selectedIndex = -1;
12046 this.store.clearFilter();
12048 this.store.filter(this.displayField, q);
12053 this.store.baseParams[this.queryParam] = q;
12055 var options = {params : this.getParams(q)};
12058 options.add = true;
12059 options.params.start = this.page * this.pageSize;
12062 this.store.load(options);
12065 * this code will make the page width larger, at the beginning, the list not align correctly,
12066 * we should expand the list on onLoad
12067 * so command out it
12072 this.selectedIndex = -1;
12077 this.loadNext = false;
12081 getParams : function(q){
12083 //p[this.queryParam] = q;
12087 p.limit = this.pageSize;
12093 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12095 collapse : function(){
12096 if(!this.isExpanded()){
12103 this.hasFocus = false;
12105 this.cancelBtn.hide();
12106 this.trigger.show();
12109 this.tickableInputEl().dom.value = '';
12110 this.tickableInputEl().blur();
12115 Roo.get(document).un('mousedown', this.collapseIf, this);
12116 Roo.get(document).un('mousewheel', this.collapseIf, this);
12117 if (!this.editable) {
12118 Roo.get(document).un('keydown', this.listKeyPress, this);
12120 this.fireEvent('collapse', this);
12124 collapseIf : function(e){
12125 var in_combo = e.within(this.el);
12126 var in_list = e.within(this.list);
12127 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12129 if (in_combo || in_list || is_list) {
12130 //e.stopPropagation();
12135 this.onTickableFooterButtonClick(e, false, false);
12143 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12145 expand : function(){
12147 if(this.isExpanded() || !this.hasFocus){
12151 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12152 this.list.setWidth(lw);
12159 this.restrictHeight();
12163 this.tickItems = Roo.apply([], this.item);
12166 this.cancelBtn.show();
12167 this.trigger.hide();
12170 this.tickableInputEl().focus();
12175 Roo.get(document).on('mousedown', this.collapseIf, this);
12176 Roo.get(document).on('mousewheel', this.collapseIf, this);
12177 if (!this.editable) {
12178 Roo.get(document).on('keydown', this.listKeyPress, this);
12181 this.fireEvent('expand', this);
12185 // Implements the default empty TriggerField.onTriggerClick function
12186 onTriggerClick : function(e)
12188 Roo.log('trigger click');
12190 if(this.disabled || !this.triggerList){
12195 this.loadNext = false;
12197 if(this.isExpanded()){
12199 if (!this.blockFocus) {
12200 this.inputEl().focus();
12204 this.hasFocus = true;
12205 if(this.triggerAction == 'all') {
12206 this.doQuery(this.allQuery, true);
12208 this.doQuery(this.getRawValue());
12210 if (!this.blockFocus) {
12211 this.inputEl().focus();
12216 onTickableTriggerClick : function(e)
12223 this.loadNext = false;
12224 this.hasFocus = true;
12226 if(this.triggerAction == 'all') {
12227 this.doQuery(this.allQuery, true);
12229 this.doQuery(this.getRawValue());
12233 onSearchFieldClick : function(e)
12235 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12236 this.onTickableFooterButtonClick(e, false, false);
12240 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12245 this.loadNext = false;
12246 this.hasFocus = true;
12248 if(this.triggerAction == 'all') {
12249 this.doQuery(this.allQuery, true);
12251 this.doQuery(this.getRawValue());
12255 listKeyPress : function(e)
12257 //Roo.log('listkeypress');
12258 // scroll to first matching element based on key pres..
12259 if (e.isSpecialKey()) {
12262 var k = String.fromCharCode(e.getKey()).toUpperCase();
12265 var csel = this.view.getSelectedNodes();
12266 var cselitem = false;
12268 var ix = this.view.indexOf(csel[0]);
12269 cselitem = this.store.getAt(ix);
12270 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12276 this.store.each(function(v) {
12278 // start at existing selection.
12279 if (cselitem.id == v.id) {
12285 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12286 match = this.store.indexOf(v);
12292 if (match === false) {
12293 return true; // no more action?
12296 this.view.select(match);
12297 var sn = Roo.get(this.view.getSelectedNodes()[0])
12298 sn.scrollIntoView(sn.dom.parentNode, false);
12301 onViewScroll : function(e, t){
12303 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){
12307 this.hasQuery = true;
12309 this.loading = this.list.select('.loading', true).first();
12311 if(this.loading === null){
12312 this.list.createChild({
12314 cls: 'loading select2-more-results select2-active',
12315 html: 'Loading more results...'
12318 this.loading = this.list.select('.loading', true).first();
12320 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12322 this.loading.hide();
12325 this.loading.show();
12330 this.loadNext = true;
12332 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12337 addItem : function(o)
12339 var dv = ''; // display value
12341 if (this.displayField) {
12342 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12344 // this is an error condition!!!
12345 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12352 var choice = this.choices.createChild({
12354 cls: 'select2-search-choice',
12363 cls: 'select2-search-choice-close',
12368 }, this.searchField);
12370 var close = choice.select('a.select2-search-choice-close', true).first()
12372 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12380 this.inputEl().dom.value = '';
12385 onRemoveItem : function(e, _self, o)
12387 e.preventDefault();
12389 this.lastItem = Roo.apply([], this.item);
12391 var index = this.item.indexOf(o.data) * 1;
12394 Roo.log('not this item?!');
12398 this.item.splice(index, 1);
12403 this.fireEvent('remove', this, e);
12409 syncValue : function()
12411 if(!this.item.length){
12418 Roo.each(this.item, function(i){
12419 if(_this.valueField){
12420 value.push(i[_this.valueField]);
12427 this.value = value.join(',');
12429 if(this.hiddenField){
12430 this.hiddenField.dom.value = this.value;
12434 clearItem : function()
12436 if(!this.multiple){
12442 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12451 inputEl: function ()
12454 return this.searchField;
12456 return this.el.select('input.form-control',true).first();
12460 onTickableFooterButtonClick : function(e, btn, el)
12462 e.preventDefault();
12464 this.lastItem = Roo.apply([], this.item);
12466 if(btn && btn.name == 'cancel'){
12467 this.tickItems = Roo.apply([], this.item);
12476 Roo.each(this.tickItems, function(o){
12484 validate : function()
12486 var v = this.getRawValue();
12489 v = this.getValue();
12492 if(this.disabled || this.allowBlank || v.length){
12497 this.markInvalid();
12501 tickableInputEl : function()
12503 if(!this.tickable || !this.editable){
12504 return this.inputEl();
12507 return this.inputEl().select('.select2-search-field-input', true).first();
12513 * @cfg {Boolean} grow
12517 * @cfg {Number} growMin
12521 * @cfg {Number} growMax
12531 * Ext JS Library 1.1.1
12532 * Copyright(c) 2006-2007, Ext JS, LLC.
12534 * Originally Released Under LGPL - original licence link has changed is not relivant.
12537 * <script type="text/javascript">
12542 * @extends Roo.util.Observable
12543 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12544 * This class also supports single and multi selection modes. <br>
12545 * Create a data model bound view:
12547 var store = new Roo.data.Store(...);
12549 var view = new Roo.View({
12551 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12553 singleSelect: true,
12554 selectedClass: "ydataview-selected",
12558 // listen for node click?
12559 view.on("click", function(vw, index, node, e){
12560 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12564 dataModel.load("foobar.xml");
12566 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12568 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12569 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12571 * Note: old style constructor is still suported (container, template, config)
12574 * Create a new View
12575 * @param {Object} config The config object
12578 Roo.View = function(config, depreciated_tpl, depreciated_config){
12580 this.parent = false;
12582 if (typeof(depreciated_tpl) == 'undefined') {
12583 // new way.. - universal constructor.
12584 Roo.apply(this, config);
12585 this.el = Roo.get(this.el);
12588 this.el = Roo.get(config);
12589 this.tpl = depreciated_tpl;
12590 Roo.apply(this, depreciated_config);
12592 this.wrapEl = this.el.wrap().wrap();
12593 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12596 if(typeof(this.tpl) == "string"){
12597 this.tpl = new Roo.Template(this.tpl);
12599 // support xtype ctors..
12600 this.tpl = new Roo.factory(this.tpl, Roo);
12604 this.tpl.compile();
12609 * @event beforeclick
12610 * Fires before a click is processed. Returns false to cancel the default action.
12611 * @param {Roo.View} this
12612 * @param {Number} index The index of the target node
12613 * @param {HTMLElement} node The target node
12614 * @param {Roo.EventObject} e The raw event object
12616 "beforeclick" : true,
12619 * Fires when a template node is clicked.
12620 * @param {Roo.View} this
12621 * @param {Number} index The index of the target node
12622 * @param {HTMLElement} node The target node
12623 * @param {Roo.EventObject} e The raw event object
12628 * Fires when a template node is double clicked.
12629 * @param {Roo.View} this
12630 * @param {Number} index The index of the target node
12631 * @param {HTMLElement} node The target node
12632 * @param {Roo.EventObject} e The raw event object
12636 * @event contextmenu
12637 * Fires when a template node is right clicked.
12638 * @param {Roo.View} this
12639 * @param {Number} index The index of the target node
12640 * @param {HTMLElement} node The target node
12641 * @param {Roo.EventObject} e The raw event object
12643 "contextmenu" : true,
12645 * @event selectionchange
12646 * Fires when the selected nodes change.
12647 * @param {Roo.View} this
12648 * @param {Array} selections Array of the selected nodes
12650 "selectionchange" : true,
12653 * @event beforeselect
12654 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12655 * @param {Roo.View} this
12656 * @param {HTMLElement} node The node to be selected
12657 * @param {Array} selections Array of currently selected nodes
12659 "beforeselect" : true,
12661 * @event preparedata
12662 * Fires on every row to render, to allow you to change the data.
12663 * @param {Roo.View} this
12664 * @param {Object} data to be rendered (change this)
12666 "preparedata" : true
12674 "click": this.onClick,
12675 "dblclick": this.onDblClick,
12676 "contextmenu": this.onContextMenu,
12680 this.selections = [];
12682 this.cmp = new Roo.CompositeElementLite([]);
12684 this.store = Roo.factory(this.store, Roo.data);
12685 this.setStore(this.store, true);
12688 if ( this.footer && this.footer.xtype) {
12690 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12692 this.footer.dataSource = this.store
12693 this.footer.container = fctr;
12694 this.footer = Roo.factory(this.footer, Roo);
12695 fctr.insertFirst(this.el);
12697 // this is a bit insane - as the paging toolbar seems to detach the el..
12698 // dom.parentNode.parentNode.parentNode
12699 // they get detached?
12703 Roo.View.superclass.constructor.call(this);
12708 Roo.extend(Roo.View, Roo.util.Observable, {
12711 * @cfg {Roo.data.Store} store Data store to load data from.
12716 * @cfg {String|Roo.Element} el The container element.
12721 * @cfg {String|Roo.Template} tpl The template used by this View
12725 * @cfg {String} dataName the named area of the template to use as the data area
12726 * Works with domtemplates roo-name="name"
12730 * @cfg {String} selectedClass The css class to add to selected nodes
12732 selectedClass : "x-view-selected",
12734 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12739 * @cfg {String} text to display on mask (default Loading)
12743 * @cfg {Boolean} multiSelect Allow multiple selection
12745 multiSelect : false,
12747 * @cfg {Boolean} singleSelect Allow single selection
12749 singleSelect: false,
12752 * @cfg {Boolean} toggleSelect - selecting
12754 toggleSelect : false,
12757 * @cfg {Boolean} tickable - selecting
12762 * Returns the element this view is bound to.
12763 * @return {Roo.Element}
12765 getEl : function(){
12766 return this.wrapEl;
12772 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12774 refresh : function(){
12775 //Roo.log('refresh');
12778 // if we are using something like 'domtemplate', then
12779 // the what gets used is:
12780 // t.applySubtemplate(NAME, data, wrapping data..)
12781 // the outer template then get' applied with
12782 // the store 'extra data'
12783 // and the body get's added to the
12784 // roo-name="data" node?
12785 // <span class='roo-tpl-{name}'></span> ?????
12789 this.clearSelections();
12790 this.el.update("");
12792 var records = this.store.getRange();
12793 if(records.length < 1) {
12795 // is this valid?? = should it render a template??
12797 this.el.update(this.emptyText);
12801 if (this.dataName) {
12802 this.el.update(t.apply(this.store.meta)); //????
12803 el = this.el.child('.roo-tpl-' + this.dataName);
12806 for(var i = 0, len = records.length; i < len; i++){
12807 var data = this.prepareData(records[i].data, i, records[i]);
12808 this.fireEvent("preparedata", this, data, i, records[i]);
12810 var d = Roo.apply({}, data);
12813 Roo.apply(d, {'roo-id' : Roo.id()});
12817 Roo.each(this.parent.item, function(item){
12818 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12821 Roo.apply(d, {'roo-data-checked' : 'checked'});
12825 html[html.length] = Roo.util.Format.trim(
12827 t.applySubtemplate(this.dataName, d, this.store.meta) :
12834 el.update(html.join(""));
12835 this.nodes = el.dom.childNodes;
12836 this.updateIndexes(0);
12841 * Function to override to reformat the data that is sent to
12842 * the template for each node.
12843 * DEPRICATED - use the preparedata event handler.
12844 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12845 * a JSON object for an UpdateManager bound view).
12847 prepareData : function(data, index, record)
12849 this.fireEvent("preparedata", this, data, index, record);
12853 onUpdate : function(ds, record){
12854 // Roo.log('on update');
12855 this.clearSelections();
12856 var index = this.store.indexOf(record);
12857 var n = this.nodes[index];
12858 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12859 n.parentNode.removeChild(n);
12860 this.updateIndexes(index, index);
12866 onAdd : function(ds, records, index)
12868 //Roo.log(['on Add', ds, records, index] );
12869 this.clearSelections();
12870 if(this.nodes.length == 0){
12874 var n = this.nodes[index];
12875 for(var i = 0, len = records.length; i < len; i++){
12876 var d = this.prepareData(records[i].data, i, records[i]);
12878 this.tpl.insertBefore(n, d);
12881 this.tpl.append(this.el, d);
12884 this.updateIndexes(index);
12887 onRemove : function(ds, record, index){
12888 // Roo.log('onRemove');
12889 this.clearSelections();
12890 var el = this.dataName ?
12891 this.el.child('.roo-tpl-' + this.dataName) :
12894 el.dom.removeChild(this.nodes[index]);
12895 this.updateIndexes(index);
12899 * Refresh an individual node.
12900 * @param {Number} index
12902 refreshNode : function(index){
12903 this.onUpdate(this.store, this.store.getAt(index));
12906 updateIndexes : function(startIndex, endIndex){
12907 var ns = this.nodes;
12908 startIndex = startIndex || 0;
12909 endIndex = endIndex || ns.length - 1;
12910 for(var i = startIndex; i <= endIndex; i++){
12911 ns[i].nodeIndex = i;
12916 * Changes the data store this view uses and refresh the view.
12917 * @param {Store} store
12919 setStore : function(store, initial){
12920 if(!initial && this.store){
12921 this.store.un("datachanged", this.refresh);
12922 this.store.un("add", this.onAdd);
12923 this.store.un("remove", this.onRemove);
12924 this.store.un("update", this.onUpdate);
12925 this.store.un("clear", this.refresh);
12926 this.store.un("beforeload", this.onBeforeLoad);
12927 this.store.un("load", this.onLoad);
12928 this.store.un("loadexception", this.onLoad);
12932 store.on("datachanged", this.refresh, this);
12933 store.on("add", this.onAdd, this);
12934 store.on("remove", this.onRemove, this);
12935 store.on("update", this.onUpdate, this);
12936 store.on("clear", this.refresh, this);
12937 store.on("beforeload", this.onBeforeLoad, this);
12938 store.on("load", this.onLoad, this);
12939 store.on("loadexception", this.onLoad, this);
12947 * onbeforeLoad - masks the loading area.
12950 onBeforeLoad : function(store,opts)
12952 //Roo.log('onBeforeLoad');
12954 this.el.update("");
12956 this.el.mask(this.mask ? this.mask : "Loading" );
12958 onLoad : function ()
12965 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12966 * @param {HTMLElement} node
12967 * @return {HTMLElement} The template node
12969 findItemFromChild : function(node){
12970 var el = this.dataName ?
12971 this.el.child('.roo-tpl-' + this.dataName,true) :
12974 if(!node || node.parentNode == el){
12977 var p = node.parentNode;
12978 while(p && p != el){
12979 if(p.parentNode == el){
12988 onClick : function(e){
12989 var item = this.findItemFromChild(e.getTarget());
12991 var index = this.indexOf(item);
12992 if(this.onItemClick(item, index, e) !== false){
12993 this.fireEvent("click", this, index, item, e);
12996 this.clearSelections();
13001 onContextMenu : function(e){
13002 var item = this.findItemFromChild(e.getTarget());
13004 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13009 onDblClick : function(e){
13010 var item = this.findItemFromChild(e.getTarget());
13012 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13016 onItemClick : function(item, index, e)
13018 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13021 if (this.toggleSelect) {
13022 var m = this.isSelected(item) ? 'unselect' : 'select';
13025 _t[m](item, true, false);
13028 if(this.multiSelect || this.singleSelect){
13029 if(this.multiSelect && e.shiftKey && this.lastSelection){
13030 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13032 this.select(item, this.multiSelect && e.ctrlKey);
13033 this.lastSelection = item;
13036 if(!this.tickable){
13037 e.preventDefault();
13045 * Get the number of selected nodes.
13048 getSelectionCount : function(){
13049 return this.selections.length;
13053 * Get the currently selected nodes.
13054 * @return {Array} An array of HTMLElements
13056 getSelectedNodes : function(){
13057 return this.selections;
13061 * Get the indexes of the selected nodes.
13064 getSelectedIndexes : function(){
13065 var indexes = [], s = this.selections;
13066 for(var i = 0, len = s.length; i < len; i++){
13067 indexes.push(s[i].nodeIndex);
13073 * Clear all selections
13074 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13076 clearSelections : function(suppressEvent){
13077 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13078 this.cmp.elements = this.selections;
13079 this.cmp.removeClass(this.selectedClass);
13080 this.selections = [];
13081 if(!suppressEvent){
13082 this.fireEvent("selectionchange", this, this.selections);
13088 * Returns true if the passed node is selected
13089 * @param {HTMLElement/Number} node The node or node index
13090 * @return {Boolean}
13092 isSelected : function(node){
13093 var s = this.selections;
13097 node = this.getNode(node);
13098 return s.indexOf(node) !== -1;
13103 * @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
13104 * @param {Boolean} keepExisting (optional) true to keep existing selections
13105 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13107 select : function(nodeInfo, keepExisting, suppressEvent){
13108 if(nodeInfo instanceof Array){
13110 this.clearSelections(true);
13112 for(var i = 0, len = nodeInfo.length; i < len; i++){
13113 this.select(nodeInfo[i], true, true);
13117 var node = this.getNode(nodeInfo);
13118 if(!node || this.isSelected(node)){
13119 return; // already selected.
13122 this.clearSelections(true);
13125 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13126 Roo.fly(node).addClass(this.selectedClass);
13127 this.selections.push(node);
13128 if(!suppressEvent){
13129 this.fireEvent("selectionchange", this, this.selections);
13137 * @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
13138 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13139 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13141 unselect : function(nodeInfo, keepExisting, suppressEvent)
13143 if(nodeInfo instanceof Array){
13144 Roo.each(this.selections, function(s) {
13145 this.unselect(s, nodeInfo);
13149 var node = this.getNode(nodeInfo);
13150 if(!node || !this.isSelected(node)){
13151 //Roo.log("not selected");
13152 return; // not selected.
13156 Roo.each(this.selections, function(s) {
13158 Roo.fly(node).removeClass(this.selectedClass);
13165 this.selections= ns;
13166 this.fireEvent("selectionchange", this, this.selections);
13170 * Gets a template node.
13171 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13172 * @return {HTMLElement} The node or null if it wasn't found
13174 getNode : function(nodeInfo){
13175 if(typeof nodeInfo == "string"){
13176 return document.getElementById(nodeInfo);
13177 }else if(typeof nodeInfo == "number"){
13178 return this.nodes[nodeInfo];
13184 * Gets a range template nodes.
13185 * @param {Number} startIndex
13186 * @param {Number} endIndex
13187 * @return {Array} An array of nodes
13189 getNodes : function(start, end){
13190 var ns = this.nodes;
13191 start = start || 0;
13192 end = typeof end == "undefined" ? ns.length - 1 : end;
13195 for(var i = start; i <= end; i++){
13199 for(var i = start; i >= end; i--){
13207 * Finds the index of the passed node
13208 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13209 * @return {Number} The index of the node or -1
13211 indexOf : function(node){
13212 node = this.getNode(node);
13213 if(typeof node.nodeIndex == "number"){
13214 return node.nodeIndex;
13216 var ns = this.nodes;
13217 for(var i = 0, len = ns.length; i < len; i++){
13228 * based on jquery fullcalendar
13232 Roo.bootstrap = Roo.bootstrap || {};
13234 * @class Roo.bootstrap.Calendar
13235 * @extends Roo.bootstrap.Component
13236 * Bootstrap Calendar class
13237 * @cfg {Boolean} loadMask (true|false) default false
13238 * @cfg {Object} header generate the user specific header of the calendar, default false
13241 * Create a new Container
13242 * @param {Object} config The config object
13247 Roo.bootstrap.Calendar = function(config){
13248 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13252 * Fires when a date is selected
13253 * @param {DatePicker} this
13254 * @param {Date} date The selected date
13258 * @event monthchange
13259 * Fires when the displayed month changes
13260 * @param {DatePicker} this
13261 * @param {Date} date The selected month
13263 'monthchange': true,
13265 * @event evententer
13266 * Fires when mouse over an event
13267 * @param {Calendar} this
13268 * @param {event} Event
13270 'evententer': true,
13272 * @event eventleave
13273 * Fires when the mouse leaves an
13274 * @param {Calendar} this
13277 'eventleave': true,
13279 * @event eventclick
13280 * Fires when the mouse click an
13281 * @param {Calendar} this
13290 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13293 * @cfg {Number} startDay
13294 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13302 getAutoCreate : function(){
13305 var fc_button = function(name, corner, style, content ) {
13306 return Roo.apply({},{
13308 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13310 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13313 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13324 style : 'width:100%',
13331 cls : 'fc-header-left',
13333 fc_button('prev', 'left', 'arrow', '‹' ),
13334 fc_button('next', 'right', 'arrow', '›' ),
13335 { tag: 'span', cls: 'fc-header-space' },
13336 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13344 cls : 'fc-header-center',
13348 cls: 'fc-header-title',
13351 html : 'month / year'
13359 cls : 'fc-header-right',
13361 /* fc_button('month', 'left', '', 'month' ),
13362 fc_button('week', '', '', 'week' ),
13363 fc_button('day', 'right', '', 'day' )
13375 header = this.header;
13378 var cal_heads = function() {
13380 // fixme - handle this.
13382 for (var i =0; i < Date.dayNames.length; i++) {
13383 var d = Date.dayNames[i];
13386 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13387 html : d.substring(0,3)
13391 ret[0].cls += ' fc-first';
13392 ret[6].cls += ' fc-last';
13395 var cal_cell = function(n) {
13398 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13403 cls: 'fc-day-number',
13407 cls: 'fc-day-content',
13411 style: 'position: relative;' // height: 17px;
13423 var cal_rows = function() {
13426 for (var r = 0; r < 6; r++) {
13433 for (var i =0; i < Date.dayNames.length; i++) {
13434 var d = Date.dayNames[i];
13435 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13438 row.cn[0].cls+=' fc-first';
13439 row.cn[0].cn[0].style = 'min-height:90px';
13440 row.cn[6].cls+=' fc-last';
13444 ret[0].cls += ' fc-first';
13445 ret[4].cls += ' fc-prev-last';
13446 ret[5].cls += ' fc-last';
13453 cls: 'fc-border-separate',
13454 style : 'width:100%',
13462 cls : 'fc-first fc-last',
13480 cls : 'fc-content',
13481 style : "position: relative;",
13484 cls : 'fc-view fc-view-month fc-grid',
13485 style : 'position: relative',
13486 unselectable : 'on',
13489 cls : 'fc-event-container',
13490 style : 'position:absolute;z-index:8;top:0;left:0;'
13508 initEvents : function()
13511 throw "can not find store for calendar";
13517 style: "text-align:center",
13521 style: "background-color:white;width:50%;margin:250 auto",
13525 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13536 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13538 var size = this.el.select('.fc-content', true).first().getSize();
13539 this.maskEl.setSize(size.width, size.height);
13540 this.maskEl.enableDisplayMode("block");
13541 if(!this.loadMask){
13542 this.maskEl.hide();
13545 this.store = Roo.factory(this.store, Roo.data);
13546 this.store.on('load', this.onLoad, this);
13547 this.store.on('beforeload', this.onBeforeLoad, this);
13551 this.cells = this.el.select('.fc-day',true);
13552 //Roo.log(this.cells);
13553 this.textNodes = this.el.query('.fc-day-number');
13554 this.cells.addClassOnOver('fc-state-hover');
13556 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13557 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13558 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13559 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13561 this.on('monthchange', this.onMonthChange, this);
13563 this.update(new Date().clearTime());
13566 resize : function() {
13567 var sz = this.el.getSize();
13569 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13570 this.el.select('.fc-day-content div',true).setHeight(34);
13575 showPrevMonth : function(e){
13576 this.update(this.activeDate.add("mo", -1));
13578 showToday : function(e){
13579 this.update(new Date().clearTime());
13582 showNextMonth : function(e){
13583 this.update(this.activeDate.add("mo", 1));
13587 showPrevYear : function(){
13588 this.update(this.activeDate.add("y", -1));
13592 showNextYear : function(){
13593 this.update(this.activeDate.add("y", 1));
13598 update : function(date)
13600 var vd = this.activeDate;
13601 this.activeDate = date;
13602 // if(vd && this.el){
13603 // var t = date.getTime();
13604 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13605 // Roo.log('using add remove');
13607 // this.fireEvent('monthchange', this, date);
13609 // this.cells.removeClass("fc-state-highlight");
13610 // this.cells.each(function(c){
13611 // if(c.dateValue == t){
13612 // c.addClass("fc-state-highlight");
13613 // setTimeout(function(){
13614 // try{c.dom.firstChild.focus();}catch(e){}
13624 var days = date.getDaysInMonth();
13626 var firstOfMonth = date.getFirstDateOfMonth();
13627 var startingPos = firstOfMonth.getDay()-this.startDay;
13629 if(startingPos < this.startDay){
13633 var pm = date.add(Date.MONTH, -1);
13634 var prevStart = pm.getDaysInMonth()-startingPos;
13636 this.cells = this.el.select('.fc-day',true);
13637 this.textNodes = this.el.query('.fc-day-number');
13638 this.cells.addClassOnOver('fc-state-hover');
13640 var cells = this.cells.elements;
13641 var textEls = this.textNodes;
13643 Roo.each(cells, function(cell){
13644 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13647 days += startingPos;
13649 // convert everything to numbers so it's fast
13650 var day = 86400000;
13651 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13654 //Roo.log(prevStart);
13656 var today = new Date().clearTime().getTime();
13657 var sel = date.clearTime().getTime();
13658 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13659 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13660 var ddMatch = this.disabledDatesRE;
13661 var ddText = this.disabledDatesText;
13662 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13663 var ddaysText = this.disabledDaysText;
13664 var format = this.format;
13666 var setCellClass = function(cal, cell){
13670 //Roo.log('set Cell Class');
13672 var t = d.getTime();
13676 cell.dateValue = t;
13678 cell.className += " fc-today";
13679 cell.className += " fc-state-highlight";
13680 cell.title = cal.todayText;
13683 // disable highlight in other month..
13684 //cell.className += " fc-state-highlight";
13689 cell.className = " fc-state-disabled";
13690 cell.title = cal.minText;
13694 cell.className = " fc-state-disabled";
13695 cell.title = cal.maxText;
13699 if(ddays.indexOf(d.getDay()) != -1){
13700 cell.title = ddaysText;
13701 cell.className = " fc-state-disabled";
13704 if(ddMatch && format){
13705 var fvalue = d.dateFormat(format);
13706 if(ddMatch.test(fvalue)){
13707 cell.title = ddText.replace("%0", fvalue);
13708 cell.className = " fc-state-disabled";
13712 if (!cell.initialClassName) {
13713 cell.initialClassName = cell.dom.className;
13716 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13721 for(; i < startingPos; i++) {
13722 textEls[i].innerHTML = (++prevStart);
13723 d.setDate(d.getDate()+1);
13725 cells[i].className = "fc-past fc-other-month";
13726 setCellClass(this, cells[i]);
13731 for(; i < days; i++){
13732 intDay = i - startingPos + 1;
13733 textEls[i].innerHTML = (intDay);
13734 d.setDate(d.getDate()+1);
13736 cells[i].className = ''; // "x-date-active";
13737 setCellClass(this, cells[i]);
13741 for(; i < 42; i++) {
13742 textEls[i].innerHTML = (++extraDays);
13743 d.setDate(d.getDate()+1);
13745 cells[i].className = "fc-future fc-other-month";
13746 setCellClass(this, cells[i]);
13749 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13751 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13753 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13754 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13756 if(totalRows != 6){
13757 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13758 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13761 this.fireEvent('monthchange', this, date);
13765 if(!this.internalRender){
13766 var main = this.el.dom.firstChild;
13767 var w = main.offsetWidth;
13768 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13769 Roo.fly(main).setWidth(w);
13770 this.internalRender = true;
13771 // opera does not respect the auto grow header center column
13772 // then, after it gets a width opera refuses to recalculate
13773 // without a second pass
13774 if(Roo.isOpera && !this.secondPass){
13775 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13776 this.secondPass = true;
13777 this.update.defer(10, this, [date]);
13784 findCell : function(dt) {
13785 dt = dt.clearTime().getTime();
13787 this.cells.each(function(c){
13788 //Roo.log("check " +c.dateValue + '?=' + dt);
13789 if(c.dateValue == dt){
13799 findCells : function(ev) {
13800 var s = ev.start.clone().clearTime().getTime();
13802 var e= ev.end.clone().clearTime().getTime();
13805 this.cells.each(function(c){
13806 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13808 if(c.dateValue > e){
13811 if(c.dateValue < s){
13820 // findBestRow: function(cells)
13824 // for (var i =0 ; i < cells.length;i++) {
13825 // ret = Math.max(cells[i].rows || 0,ret);
13832 addItem : function(ev)
13834 // look for vertical location slot in
13835 var cells = this.findCells(ev);
13837 // ev.row = this.findBestRow(cells);
13839 // work out the location.
13843 for(var i =0; i < cells.length; i++) {
13845 cells[i].row = cells[0].row;
13848 cells[i].row = cells[i].row + 1;
13858 if (crow.start.getY() == cells[i].getY()) {
13860 crow.end = cells[i];
13877 cells[0].events.push(ev);
13879 this.calevents.push(ev);
13882 clearEvents: function() {
13884 if(!this.calevents){
13888 Roo.each(this.cells.elements, function(c){
13894 Roo.each(this.calevents, function(e) {
13895 Roo.each(e.els, function(el) {
13896 el.un('mouseenter' ,this.onEventEnter, this);
13897 el.un('mouseleave' ,this.onEventLeave, this);
13902 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13908 renderEvents: function()
13912 this.cells.each(function(c) {
13921 if(c.row != c.events.length){
13922 r = 4 - (4 - (c.row - c.events.length));
13925 c.events = ev.slice(0, r);
13926 c.more = ev.slice(r);
13928 if(c.more.length && c.more.length == 1){
13929 c.events.push(c.more.pop());
13932 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13936 this.cells.each(function(c) {
13938 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13941 for (var e = 0; e < c.events.length; e++){
13942 var ev = c.events[e];
13943 var rows = ev.rows;
13945 for(var i = 0; i < rows.length; i++) {
13947 // how many rows should it span..
13950 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13951 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13953 unselectable : "on",
13956 cls: 'fc-event-inner',
13960 // cls: 'fc-event-time',
13961 // html : cells.length > 1 ? '' : ev.time
13965 cls: 'fc-event-title',
13966 html : String.format('{0}', ev.title)
13973 cls: 'ui-resizable-handle ui-resizable-e',
13974 html : '  '
13981 cfg.cls += ' fc-event-start';
13983 if ((i+1) == rows.length) {
13984 cfg.cls += ' fc-event-end';
13987 var ctr = _this.el.select('.fc-event-container',true).first();
13988 var cg = ctr.createChild(cfg);
13990 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13991 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13993 var r = (c.more.length) ? 1 : 0;
13994 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13995 cg.setWidth(ebox.right - sbox.x -2);
13997 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13998 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13999 cg.on('click', _this.onEventClick, _this, ev);
14010 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14011 style : 'position: absolute',
14012 unselectable : "on",
14015 cls: 'fc-event-inner',
14019 cls: 'fc-event-title',
14027 cls: 'ui-resizable-handle ui-resizable-e',
14028 html : '  '
14034 var ctr = _this.el.select('.fc-event-container',true).first();
14035 var cg = ctr.createChild(cfg);
14037 var sbox = c.select('.fc-day-content',true).first().getBox();
14038 var ebox = c.select('.fc-day-content',true).first().getBox();
14040 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14041 cg.setWidth(ebox.right - sbox.x -2);
14043 cg.on('click', _this.onMoreEventClick, _this, c.more);
14053 onEventEnter: function (e, el,event,d) {
14054 this.fireEvent('evententer', this, el, event);
14057 onEventLeave: function (e, el,event,d) {
14058 this.fireEvent('eventleave', this, el, event);
14061 onEventClick: function (e, el,event,d) {
14062 this.fireEvent('eventclick', this, el, event);
14065 onMonthChange: function () {
14069 onMoreEventClick: function(e, el, more)
14073 this.calpopover.placement = 'right';
14074 this.calpopover.setTitle('More');
14076 this.calpopover.setContent('');
14078 var ctr = this.calpopover.el.select('.popover-content', true).first();
14080 Roo.each(more, function(m){
14082 cls : 'fc-event-hori fc-event-draggable',
14085 var cg = ctr.createChild(cfg);
14087 cg.on('click', _this.onEventClick, _this, m);
14090 this.calpopover.show(el);
14095 onLoad: function ()
14097 this.calevents = [];
14100 if(this.store.getCount() > 0){
14101 this.store.data.each(function(d){
14104 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14105 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14106 time : d.data.start_time,
14107 title : d.data.title,
14108 description : d.data.description,
14109 venue : d.data.venue
14114 this.renderEvents();
14116 if(this.calevents.length && this.loadMask){
14117 this.maskEl.hide();
14121 onBeforeLoad: function()
14123 this.clearEvents();
14125 this.maskEl.show();
14139 * @class Roo.bootstrap.Popover
14140 * @extends Roo.bootstrap.Component
14141 * Bootstrap Popover class
14142 * @cfg {String} html contents of the popover (or false to use children..)
14143 * @cfg {String} title of popover (or false to hide)
14144 * @cfg {String} placement how it is placed
14145 * @cfg {String} trigger click || hover (or false to trigger manually)
14146 * @cfg {String} over what (parent or false to trigger manually.)
14147 * @cfg {Number} delay - delay before showing
14150 * Create a new Popover
14151 * @param {Object} config The config object
14154 Roo.bootstrap.Popover = function(config){
14155 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14158 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14160 title: 'Fill in a title',
14163 placement : 'right',
14164 trigger : 'hover', // hover
14170 can_build_overlaid : false,
14172 getChildContainer : function()
14174 return this.el.select('.popover-content',true).first();
14177 getAutoCreate : function(){
14178 Roo.log('make popover?');
14180 cls : 'popover roo-dynamic',
14181 style: 'display:block',
14187 cls : 'popover-inner',
14191 cls: 'popover-title',
14195 cls : 'popover-content',
14206 setTitle: function(str)
14208 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14210 setContent: function(str)
14212 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14214 // as it get's added to the bottom of the page.
14215 onRender : function(ct, position)
14217 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14219 var cfg = Roo.apply({}, this.getAutoCreate());
14223 cfg.cls += ' ' + this.cls;
14226 cfg.style = this.style;
14228 Roo.log("adding to ")
14229 this.el = Roo.get(document.body).createChild(cfg, position);
14235 initEvents : function()
14237 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14238 this.el.enableDisplayMode('block');
14240 if (this.over === false) {
14243 if (this.triggers === false) {
14246 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14247 var triggers = this.trigger ? this.trigger.split(' ') : [];
14248 Roo.each(triggers, function(trigger) {
14250 if (trigger == 'click') {
14251 on_el.on('click', this.toggle, this);
14252 } else if (trigger != 'manual') {
14253 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14254 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14256 on_el.on(eventIn ,this.enter, this);
14257 on_el.on(eventOut, this.leave, this);
14268 toggle : function () {
14269 this.hoverState == 'in' ? this.leave() : this.enter();
14272 enter : function () {
14275 clearTimeout(this.timeout);
14277 this.hoverState = 'in';
14279 if (!this.delay || !this.delay.show) {
14284 this.timeout = setTimeout(function () {
14285 if (_t.hoverState == 'in') {
14288 }, this.delay.show)
14290 leave : function() {
14291 clearTimeout(this.timeout);
14293 this.hoverState = 'out';
14295 if (!this.delay || !this.delay.hide) {
14300 this.timeout = setTimeout(function () {
14301 if (_t.hoverState == 'out') {
14304 }, this.delay.hide)
14307 show : function (on_el)
14310 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14313 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14314 if (this.html !== false) {
14315 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14317 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14318 if (!this.title.length) {
14319 this.el.select('.popover-title',true).hide();
14322 var placement = typeof this.placement == 'function' ?
14323 this.placement.call(this, this.el, on_el) :
14326 var autoToken = /\s?auto?\s?/i;
14327 var autoPlace = autoToken.test(placement);
14329 placement = placement.replace(autoToken, '') || 'top';
14333 //this.el.setXY([0,0]);
14335 this.el.dom.style.display='block';
14336 this.el.addClass(placement);
14338 //this.el.appendTo(on_el);
14340 var p = this.getPosition();
14341 var box = this.el.getBox();
14346 var align = Roo.bootstrap.Popover.alignment[placement];
14347 this.el.alignTo(on_el, align[0],align[1]);
14348 //var arrow = this.el.select('.arrow',true).first();
14349 //arrow.set(align[2],
14351 this.el.addClass('in');
14352 this.hoverState = null;
14354 if (this.el.hasClass('fade')) {
14361 this.el.setXY([0,0]);
14362 this.el.removeClass('in');
14369 Roo.bootstrap.Popover.alignment = {
14370 'left' : ['r-l', [-10,0], 'right'],
14371 'right' : ['l-r', [10,0], 'left'],
14372 'bottom' : ['t-b', [0,10], 'top'],
14373 'top' : [ 'b-t', [0,-10], 'bottom']
14384 * @class Roo.bootstrap.Progress
14385 * @extends Roo.bootstrap.Component
14386 * Bootstrap Progress class
14387 * @cfg {Boolean} striped striped of the progress bar
14388 * @cfg {Boolean} active animated of the progress bar
14392 * Create a new Progress
14393 * @param {Object} config The config object
14396 Roo.bootstrap.Progress = function(config){
14397 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14400 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14405 getAutoCreate : function(){
14413 cfg.cls += ' progress-striped';
14417 cfg.cls += ' active';
14436 * @class Roo.bootstrap.ProgressBar
14437 * @extends Roo.bootstrap.Component
14438 * Bootstrap ProgressBar class
14439 * @cfg {Number} aria_valuenow aria-value now
14440 * @cfg {Number} aria_valuemin aria-value min
14441 * @cfg {Number} aria_valuemax aria-value max
14442 * @cfg {String} label label for the progress bar
14443 * @cfg {String} panel (success | info | warning | danger )
14444 * @cfg {String} role role of the progress bar
14445 * @cfg {String} sr_only text
14449 * Create a new ProgressBar
14450 * @param {Object} config The config object
14453 Roo.bootstrap.ProgressBar = function(config){
14454 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14457 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14461 aria_valuemax : 100,
14467 getAutoCreate : function()
14472 cls: 'progress-bar',
14473 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14485 cfg.role = this.role;
14488 if(this.aria_valuenow){
14489 cfg['aria-valuenow'] = this.aria_valuenow;
14492 if(this.aria_valuemin){
14493 cfg['aria-valuemin'] = this.aria_valuemin;
14496 if(this.aria_valuemax){
14497 cfg['aria-valuemax'] = this.aria_valuemax;
14500 if(this.label && !this.sr_only){
14501 cfg.html = this.label;
14505 cfg.cls += ' progress-bar-' + this.panel;
14511 update : function(aria_valuenow)
14513 this.aria_valuenow = aria_valuenow;
14515 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14530 * @class Roo.bootstrap.TabGroup
14531 * @extends Roo.bootstrap.Column
14532 * Bootstrap Column class
14533 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14534 * @cfg {Boolean} carousel true to make the group behave like a carousel
14537 * Create a new TabGroup
14538 * @param {Object} config The config object
14541 Roo.bootstrap.TabGroup = function(config){
14542 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14544 this.navId = Roo.id();
14547 Roo.bootstrap.TabGroup.register(this);
14551 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14554 transition : false,
14556 getAutoCreate : function()
14558 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14560 cfg.cls += ' tab-content';
14562 if (this.carousel) {
14563 cfg.cls += ' carousel slide';
14565 cls : 'carousel-inner'
14572 getChildContainer : function()
14574 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14578 * register a Navigation item
14579 * @param {Roo.bootstrap.NavItem} the navitem to add
14581 register : function(item)
14583 this.tabs.push( item);
14584 item.navId = this.navId; // not really needed..
14588 getActivePanel : function()
14591 Roo.each(this.tabs, function(t) {
14601 getPanelByName : function(n)
14604 Roo.each(this.tabs, function(t) {
14605 if (t.tabId == n) {
14613 indexOfPanel : function(p)
14616 Roo.each(this.tabs, function(t,i) {
14617 if (t.tabId == p.tabId) {
14626 * show a specific panel
14627 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14628 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14630 showPanel : function (pan)
14633 if (typeof(pan) == 'number') {
14634 pan = this.tabs[pan];
14636 if (typeof(pan) == 'string') {
14637 pan = this.getPanelByName(pan);
14639 if (pan.tabId == this.getActivePanel().tabId) {
14642 var cur = this.getActivePanel();
14644 if (false === cur.fireEvent('beforedeactivate')) {
14648 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14650 this.transition = true;
14651 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14652 var lr = dir == 'next' ? 'left' : 'right';
14653 pan.el.addClass(dir); // or prev
14654 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14655 cur.el.addClass(lr); // or right
14656 pan.el.addClass(lr);
14659 cur.el.on('transitionend', function() {
14660 Roo.log("trans end?");
14662 pan.el.removeClass([lr,dir]);
14663 pan.setActive(true);
14665 cur.el.removeClass([lr]);
14666 cur.setActive(false);
14668 _this.transition = false;
14670 }, this, { single: true } );
14674 cur.setActive(false);
14675 pan.setActive(true);
14679 showPanelNext : function()
14681 var i = this.indexOfPanel(this.getActivePanel());
14682 if (i > this.tabs.length) {
14685 this.showPanel(this.tabs[i+1]);
14687 showPanelPrev : function()
14689 var i = this.indexOfPanel(this.getActivePanel());
14693 this.showPanel(this.tabs[i-1]);
14704 Roo.apply(Roo.bootstrap.TabGroup, {
14708 * register a Navigation Group
14709 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14711 register : function(navgrp)
14713 this.groups[navgrp.navId] = navgrp;
14717 * fetch a Navigation Group based on the navigation ID
14718 * if one does not exist , it will get created.
14719 * @param {string} the navgroup to add
14720 * @returns {Roo.bootstrap.NavGroup} the navgroup
14722 get: function(navId) {
14723 if (typeof(this.groups[navId]) == 'undefined') {
14724 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14726 return this.groups[navId] ;
14741 * @class Roo.bootstrap.TabPanel
14742 * @extends Roo.bootstrap.Component
14743 * Bootstrap TabPanel class
14744 * @cfg {Boolean} active panel active
14745 * @cfg {String} html panel content
14746 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14747 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14751 * Create a new TabPanel
14752 * @param {Object} config The config object
14755 Roo.bootstrap.TabPanel = function(config){
14756 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14760 * Fires when the active status changes
14761 * @param {Roo.bootstrap.TabPanel} this
14762 * @param {Boolean} state the new state
14767 * @event beforedeactivate
14768 * Fires before a tab is de-activated - can be used to do validation on a form.
14769 * @param {Roo.bootstrap.TabPanel} this
14770 * @return {Boolean} false if there is an error
14773 'beforedeactivate': true
14776 this.tabId = this.tabId || Roo.id();
14780 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14787 getAutoCreate : function(){
14790 // item is needed for carousel - not sure if it has any effect otherwise
14791 cls: 'tab-pane item',
14792 html: this.html || ''
14796 cfg.cls += ' active';
14800 cfg.tabId = this.tabId;
14807 initEvents: function()
14809 Roo.log('-------- init events on tab panel ---------');
14811 var p = this.parent();
14812 this.navId = this.navId || p.navId;
14814 if (typeof(this.navId) != 'undefined') {
14815 // not really needed.. but just in case.. parent should be a NavGroup.
14816 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14817 Roo.log(['register', tg, this]);
14823 onRender : function(ct, position)
14825 // Roo.log("Call onRender: " + this.xtype);
14827 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14835 setActive: function(state)
14837 Roo.log("panel - set active " + this.tabId + "=" + state);
14839 this.active = state;
14841 this.el.removeClass('active');
14843 } else if (!this.el.hasClass('active')) {
14844 this.el.addClass('active');
14846 this.fireEvent('changed', this, state);
14863 * @class Roo.bootstrap.DateField
14864 * @extends Roo.bootstrap.Input
14865 * Bootstrap DateField class
14866 * @cfg {Number} weekStart default 0
14867 * @cfg {String} viewMode default empty, (months|years)
14868 * @cfg {String} minViewMode default empty, (months|years)
14869 * @cfg {Number} startDate default -Infinity
14870 * @cfg {Number} endDate default Infinity
14871 * @cfg {Boolean} todayHighlight default false
14872 * @cfg {Boolean} todayBtn default false
14873 * @cfg {Boolean} calendarWeeks default false
14874 * @cfg {Object} daysOfWeekDisabled default empty
14875 * @cfg {Boolean} singleMode default false (true | false)
14877 * @cfg {Boolean} keyboardNavigation default true
14878 * @cfg {String} language default en
14881 * Create a new DateField
14882 * @param {Object} config The config object
14885 Roo.bootstrap.DateField = function(config){
14886 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14890 * Fires when this field show.
14891 * @param {Roo.bootstrap.DateField} this
14892 * @param {Mixed} date The date value
14897 * Fires when this field hide.
14898 * @param {Roo.bootstrap.DateField} this
14899 * @param {Mixed} date The date value
14904 * Fires when select a date.
14905 * @param {Roo.bootstrap.DateField} this
14906 * @param {Mixed} date The date value
14912 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14915 * @cfg {String} format
14916 * The default date format string which can be overriden for localization support. The format must be
14917 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14921 * @cfg {String} altFormats
14922 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14923 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14925 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14933 todayHighlight : false,
14939 keyboardNavigation: true,
14941 calendarWeeks: false,
14943 startDate: -Infinity,
14947 daysOfWeekDisabled: [],
14951 singleMode : false,
14953 UTCDate: function()
14955 return new Date(Date.UTC.apply(Date, arguments));
14958 UTCToday: function()
14960 var today = new Date();
14961 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14964 getDate: function() {
14965 var d = this.getUTCDate();
14966 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14969 getUTCDate: function() {
14973 setDate: function(d) {
14974 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14977 setUTCDate: function(d) {
14979 this.setValue(this.formatDate(this.date));
14982 onRender: function(ct, position)
14985 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14987 this.language = this.language || 'en';
14988 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14989 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14991 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14992 this.format = this.format || 'm/d/y';
14993 this.isInline = false;
14994 this.isInput = true;
14995 this.component = this.el.select('.add-on', true).first() || false;
14996 this.component = (this.component && this.component.length === 0) ? false : this.component;
14997 this.hasInput = this.component && this.inputEL().length;
14999 if (typeof(this.minViewMode === 'string')) {
15000 switch (this.minViewMode) {
15002 this.minViewMode = 1;
15005 this.minViewMode = 2;
15008 this.minViewMode = 0;
15013 if (typeof(this.viewMode === 'string')) {
15014 switch (this.viewMode) {
15027 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15029 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15031 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15033 this.picker().on('mousedown', this.onMousedown, this);
15034 this.picker().on('click', this.onClick, this);
15036 this.picker().addClass('datepicker-dropdown');
15038 this.startViewMode = this.viewMode;
15040 if(this.singleMode){
15041 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15042 v.setVisibilityMode(Roo.Element.DISPLAY)
15046 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15047 v.setStyle('width', '189px');
15051 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15052 if(!this.calendarWeeks){
15057 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15058 v.attr('colspan', function(i, val){
15059 return parseInt(val) + 1;
15064 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15066 this.setStartDate(this.startDate);
15067 this.setEndDate(this.endDate);
15069 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15076 if(this.isInline) {
15081 picker : function()
15083 return this.pickerEl;
15084 // return this.el.select('.datepicker', true).first();
15087 fillDow: function()
15089 var dowCnt = this.weekStart;
15098 if(this.calendarWeeks){
15106 while (dowCnt < this.weekStart + 7) {
15110 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15114 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15117 fillMonths: function()
15120 var months = this.picker().select('>.datepicker-months td', true).first();
15122 months.dom.innerHTML = '';
15128 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15131 months.createChild(month);
15138 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;
15140 if (this.date < this.startDate) {
15141 this.viewDate = new Date(this.startDate);
15142 } else if (this.date > this.endDate) {
15143 this.viewDate = new Date(this.endDate);
15145 this.viewDate = new Date(this.date);
15153 var d = new Date(this.viewDate),
15154 year = d.getUTCFullYear(),
15155 month = d.getUTCMonth(),
15156 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15157 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15158 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15159 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15160 currentDate = this.date && this.date.valueOf(),
15161 today = this.UTCToday();
15163 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15165 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15167 // this.picker.select('>tfoot th.today').
15168 // .text(dates[this.language].today)
15169 // .toggle(this.todayBtn !== false);
15171 this.updateNavArrows();
15174 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15176 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15178 prevMonth.setUTCDate(day);
15180 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15182 var nextMonth = new Date(prevMonth);
15184 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15186 nextMonth = nextMonth.valueOf();
15188 var fillMonths = false;
15190 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15192 while(prevMonth.valueOf() < nextMonth) {
15195 if (prevMonth.getUTCDay() === this.weekStart) {
15197 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15205 if(this.calendarWeeks){
15206 // ISO 8601: First week contains first thursday.
15207 // ISO also states week starts on Monday, but we can be more abstract here.
15209 // Start of current week: based on weekstart/current date
15210 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15211 // Thursday of this week
15212 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15213 // First Thursday of year, year from thursday
15214 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15215 // Calendar week: ms between thursdays, div ms per day, div 7 days
15216 calWeek = (th - yth) / 864e5 / 7 + 1;
15218 fillMonths.cn.push({
15226 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15228 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15231 if (this.todayHighlight &&
15232 prevMonth.getUTCFullYear() == today.getFullYear() &&
15233 prevMonth.getUTCMonth() == today.getMonth() &&
15234 prevMonth.getUTCDate() == today.getDate()) {
15235 clsName += ' today';
15238 if (currentDate && prevMonth.valueOf() === currentDate) {
15239 clsName += ' active';
15242 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15243 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15244 clsName += ' disabled';
15247 fillMonths.cn.push({
15249 cls: 'day ' + clsName,
15250 html: prevMonth.getDate()
15253 prevMonth.setDate(prevMonth.getDate()+1);
15256 var currentYear = this.date && this.date.getUTCFullYear();
15257 var currentMonth = this.date && this.date.getUTCMonth();
15259 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15261 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15262 v.removeClass('active');
15264 if(currentYear === year && k === currentMonth){
15265 v.addClass('active');
15268 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15269 v.addClass('disabled');
15275 year = parseInt(year/10, 10) * 10;
15277 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15279 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15282 for (var i = -1; i < 11; i++) {
15283 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15285 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15293 showMode: function(dir)
15296 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15299 Roo.each(this.picker().select('>div',true).elements, function(v){
15300 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15303 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15308 if(this.isInline) return;
15310 this.picker().removeClass(['bottom', 'top']);
15312 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15314 * place to the top of element!
15318 this.picker().addClass('top');
15319 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15324 this.picker().addClass('bottom');
15326 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15329 parseDate : function(value)
15331 if(!value || value instanceof Date){
15334 var v = Date.parseDate(value, this.format);
15335 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15336 v = Date.parseDate(value, 'Y-m-d');
15338 if(!v && this.altFormats){
15339 if(!this.altFormatsArray){
15340 this.altFormatsArray = this.altFormats.split("|");
15342 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15343 v = Date.parseDate(value, this.altFormatsArray[i]);
15349 formatDate : function(date, fmt)
15351 return (!date || !(date instanceof Date)) ?
15352 date : date.dateFormat(fmt || this.format);
15355 onFocus : function()
15357 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15361 onBlur : function()
15363 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15365 var d = this.inputEl().getValue();
15374 this.picker().show();
15378 this.fireEvent('show', this, this.date);
15383 if(this.isInline) return;
15384 this.picker().hide();
15385 this.viewMode = this.startViewMode;
15388 this.fireEvent('hide', this, this.date);
15392 onMousedown: function(e)
15394 e.stopPropagation();
15395 e.preventDefault();
15400 Roo.bootstrap.DateField.superclass.keyup.call(this);
15404 setValue: function(v)
15407 // v can be a string or a date..
15410 var d = new Date(this.parseDate(v) ).clearTime();
15412 if(isNaN(d.getTime())){
15413 this.date = this.viewDate = '';
15414 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15418 v = this.formatDate(d);
15420 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15422 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15426 this.fireEvent('select', this, this.date);
15430 getValue: function()
15432 return this.formatDate(this.date);
15435 fireKey: function(e)
15437 if (!this.picker().isVisible()){
15438 if (e.keyCode == 27) // allow escape to hide and re-show picker
15443 var dateChanged = false,
15445 newDate, newViewDate;
15450 e.preventDefault();
15454 if (!this.keyboardNavigation) break;
15455 dir = e.keyCode == 37 ? -1 : 1;
15458 newDate = this.moveYear(this.date, dir);
15459 newViewDate = this.moveYear(this.viewDate, dir);
15460 } else if (e.shiftKey){
15461 newDate = this.moveMonth(this.date, dir);
15462 newViewDate = this.moveMonth(this.viewDate, dir);
15464 newDate = new Date(this.date);
15465 newDate.setUTCDate(this.date.getUTCDate() + dir);
15466 newViewDate = new Date(this.viewDate);
15467 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15469 if (this.dateWithinRange(newDate)){
15470 this.date = newDate;
15471 this.viewDate = newViewDate;
15472 this.setValue(this.formatDate(this.date));
15474 e.preventDefault();
15475 dateChanged = true;
15480 if (!this.keyboardNavigation) break;
15481 dir = e.keyCode == 38 ? -1 : 1;
15483 newDate = this.moveYear(this.date, dir);
15484 newViewDate = this.moveYear(this.viewDate, dir);
15485 } else if (e.shiftKey){
15486 newDate = this.moveMonth(this.date, dir);
15487 newViewDate = this.moveMonth(this.viewDate, dir);
15489 newDate = new Date(this.date);
15490 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15491 newViewDate = new Date(this.viewDate);
15492 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15494 if (this.dateWithinRange(newDate)){
15495 this.date = newDate;
15496 this.viewDate = newViewDate;
15497 this.setValue(this.formatDate(this.date));
15499 e.preventDefault();
15500 dateChanged = true;
15504 this.setValue(this.formatDate(this.date));
15506 e.preventDefault();
15509 this.setValue(this.formatDate(this.date));
15523 onClick: function(e)
15525 e.stopPropagation();
15526 e.preventDefault();
15528 var target = e.getTarget();
15530 if(target.nodeName.toLowerCase() === 'i'){
15531 target = Roo.get(target).dom.parentNode;
15534 var nodeName = target.nodeName;
15535 var className = target.className;
15536 var html = target.innerHTML;
15537 //Roo.log(nodeName);
15539 switch(nodeName.toLowerCase()) {
15541 switch(className) {
15547 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15548 switch(this.viewMode){
15550 this.viewDate = this.moveMonth(this.viewDate, dir);
15554 this.viewDate = this.moveYear(this.viewDate, dir);
15560 var date = new Date();
15561 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15563 this.setValue(this.formatDate(this.date));
15570 if (className.indexOf('disabled') < 0) {
15571 this.viewDate.setUTCDate(1);
15572 if (className.indexOf('month') > -1) {
15573 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15575 var year = parseInt(html, 10) || 0;
15576 this.viewDate.setUTCFullYear(year);
15580 if(this.singleMode){
15581 this.setValue(this.formatDate(this.viewDate));
15592 //Roo.log(className);
15593 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15594 var day = parseInt(html, 10) || 1;
15595 var year = this.viewDate.getUTCFullYear(),
15596 month = this.viewDate.getUTCMonth();
15598 if (className.indexOf('old') > -1) {
15605 } else if (className.indexOf('new') > -1) {
15613 //Roo.log([year,month,day]);
15614 this.date = this.UTCDate(year, month, day,0,0,0,0);
15615 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15617 //Roo.log(this.formatDate(this.date));
15618 this.setValue(this.formatDate(this.date));
15625 setStartDate: function(startDate)
15627 this.startDate = startDate || -Infinity;
15628 if (this.startDate !== -Infinity) {
15629 this.startDate = this.parseDate(this.startDate);
15632 this.updateNavArrows();
15635 setEndDate: function(endDate)
15637 this.endDate = endDate || Infinity;
15638 if (this.endDate !== Infinity) {
15639 this.endDate = this.parseDate(this.endDate);
15642 this.updateNavArrows();
15645 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15647 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15648 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15649 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15651 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15652 return parseInt(d, 10);
15655 this.updateNavArrows();
15658 updateNavArrows: function()
15660 if(this.singleMode){
15664 var d = new Date(this.viewDate),
15665 year = d.getUTCFullYear(),
15666 month = d.getUTCMonth();
15668 Roo.each(this.picker().select('.prev', true).elements, function(v){
15670 switch (this.viewMode) {
15673 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15679 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15686 Roo.each(this.picker().select('.next', true).elements, function(v){
15688 switch (this.viewMode) {
15691 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15697 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15705 moveMonth: function(date, dir)
15707 if (!dir) return date;
15708 var new_date = new Date(date.valueOf()),
15709 day = new_date.getUTCDate(),
15710 month = new_date.getUTCMonth(),
15711 mag = Math.abs(dir),
15713 dir = dir > 0 ? 1 : -1;
15716 // If going back one month, make sure month is not current month
15717 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15719 return new_date.getUTCMonth() == month;
15721 // If going forward one month, make sure month is as expected
15722 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15724 return new_date.getUTCMonth() != new_month;
15726 new_month = month + dir;
15727 new_date.setUTCMonth(new_month);
15728 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15729 if (new_month < 0 || new_month > 11)
15730 new_month = (new_month + 12) % 12;
15732 // For magnitudes >1, move one month at a time...
15733 for (var i=0; i<mag; i++)
15734 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15735 new_date = this.moveMonth(new_date, dir);
15736 // ...then reset the day, keeping it in the new month
15737 new_month = new_date.getUTCMonth();
15738 new_date.setUTCDate(day);
15740 return new_month != new_date.getUTCMonth();
15743 // Common date-resetting loop -- if date is beyond end of month, make it
15746 new_date.setUTCDate(--day);
15747 new_date.setUTCMonth(new_month);
15752 moveYear: function(date, dir)
15754 return this.moveMonth(date, dir*12);
15757 dateWithinRange: function(date)
15759 return date >= this.startDate && date <= this.endDate;
15765 this.picker().remove();
15770 Roo.apply(Roo.bootstrap.DateField, {
15781 html: '<i class="fa fa-arrow-left"/>'
15791 html: '<i class="fa fa-arrow-right"/>'
15833 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15834 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15835 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15836 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15837 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15850 navFnc: 'FullYear',
15855 navFnc: 'FullYear',
15860 Roo.apply(Roo.bootstrap.DateField, {
15864 cls: 'datepicker dropdown-menu roo-dynamic',
15868 cls: 'datepicker-days',
15872 cls: 'table-condensed',
15874 Roo.bootstrap.DateField.head,
15878 Roo.bootstrap.DateField.footer
15885 cls: 'datepicker-months',
15889 cls: 'table-condensed',
15891 Roo.bootstrap.DateField.head,
15892 Roo.bootstrap.DateField.content,
15893 Roo.bootstrap.DateField.footer
15900 cls: 'datepicker-years',
15904 cls: 'table-condensed',
15906 Roo.bootstrap.DateField.head,
15907 Roo.bootstrap.DateField.content,
15908 Roo.bootstrap.DateField.footer
15927 * @class Roo.bootstrap.TimeField
15928 * @extends Roo.bootstrap.Input
15929 * Bootstrap DateField class
15933 * Create a new TimeField
15934 * @param {Object} config The config object
15937 Roo.bootstrap.TimeField = function(config){
15938 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15942 * Fires when this field show.
15943 * @param {Roo.bootstrap.DateField} thisthis
15944 * @param {Mixed} date The date value
15949 * Fires when this field hide.
15950 * @param {Roo.bootstrap.DateField} this
15951 * @param {Mixed} date The date value
15956 * Fires when select a date.
15957 * @param {Roo.bootstrap.DateField} this
15958 * @param {Mixed} date The date value
15964 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15967 * @cfg {String} format
15968 * The default time format string which can be overriden for localization support. The format must be
15969 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15973 onRender: function(ct, position)
15976 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15978 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15980 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15982 this.pop = this.picker().select('>.datepicker-time',true).first();
15983 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15985 this.picker().on('mousedown', this.onMousedown, this);
15986 this.picker().on('click', this.onClick, this);
15988 this.picker().addClass('datepicker-dropdown');
15993 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15994 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15995 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15996 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15997 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15998 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16002 fireKey: function(e){
16003 if (!this.picker().isVisible()){
16004 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16010 e.preventDefault();
16018 this.onTogglePeriod();
16021 this.onIncrementMinutes();
16024 this.onDecrementMinutes();
16033 onClick: function(e) {
16034 e.stopPropagation();
16035 e.preventDefault();
16038 picker : function()
16040 return this.el.select('.datepicker', true).first();
16043 fillTime: function()
16045 var time = this.pop.select('tbody', true).first();
16047 time.dom.innerHTML = '';
16062 cls: 'hours-up glyphicon glyphicon-chevron-up'
16082 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16103 cls: 'timepicker-hour',
16118 cls: 'timepicker-minute',
16133 cls: 'btn btn-primary period',
16155 cls: 'hours-down glyphicon glyphicon-chevron-down'
16175 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16193 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16200 var hours = this.time.getHours();
16201 var minutes = this.time.getMinutes();
16214 hours = hours - 12;
16218 hours = '0' + hours;
16222 minutes = '0' + minutes;
16225 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16226 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16227 this.pop.select('button', true).first().dom.innerHTML = period;
16233 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16235 var cls = ['bottom'];
16237 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16244 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16249 this.picker().addClass(cls.join('-'));
16253 Roo.each(cls, function(c){
16255 _this.picker().setTop(_this.inputEl().getHeight());
16259 _this.picker().setTop(0 - _this.picker().getHeight());
16264 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16268 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16275 onFocus : function()
16277 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16281 onBlur : function()
16283 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16289 this.picker().show();
16294 this.fireEvent('show', this, this.date);
16299 this.picker().hide();
16302 this.fireEvent('hide', this, this.date);
16305 setTime : function()
16308 this.setValue(this.time.format(this.format));
16310 this.fireEvent('select', this, this.date);
16315 onMousedown: function(e){
16316 e.stopPropagation();
16317 e.preventDefault();
16320 onIncrementHours: function()
16322 Roo.log('onIncrementHours');
16323 this.time = this.time.add(Date.HOUR, 1);
16328 onDecrementHours: function()
16330 Roo.log('onDecrementHours');
16331 this.time = this.time.add(Date.HOUR, -1);
16335 onIncrementMinutes: function()
16337 Roo.log('onIncrementMinutes');
16338 this.time = this.time.add(Date.MINUTE, 1);
16342 onDecrementMinutes: function()
16344 Roo.log('onDecrementMinutes');
16345 this.time = this.time.add(Date.MINUTE, -1);
16349 onTogglePeriod: function()
16351 Roo.log('onTogglePeriod');
16352 this.time = this.time.add(Date.HOUR, 12);
16359 Roo.apply(Roo.bootstrap.TimeField, {
16389 cls: 'btn btn-info ok',
16401 Roo.apply(Roo.bootstrap.TimeField, {
16405 cls: 'datepicker dropdown-menu',
16409 cls: 'datepicker-time',
16413 cls: 'table-condensed',
16415 Roo.bootstrap.TimeField.content,
16416 Roo.bootstrap.TimeField.footer
16435 * @class Roo.bootstrap.MonthField
16436 * @extends Roo.bootstrap.Input
16437 * Bootstrap MonthField class
16439 * @cfg {String} language default en
16442 * Create a new MonthField
16443 * @param {Object} config The config object
16446 Roo.bootstrap.MonthField = function(config){
16447 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16452 * Fires when this field show.
16453 * @param {Roo.bootstrap.MonthField} this
16454 * @param {Mixed} date The date value
16459 * Fires when this field hide.
16460 * @param {Roo.bootstrap.MonthField} this
16461 * @param {Mixed} date The date value
16466 * Fires when select a date.
16467 * @param {Roo.bootstrap.MonthField} this
16468 * @param {String} oldvalue The old value
16469 * @param {String} newvalue The new value
16475 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16477 onRender: function(ct, position)
16480 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16482 this.language = this.language || 'en';
16483 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16484 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16486 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16487 this.isInline = false;
16488 this.isInput = true;
16489 this.component = this.el.select('.add-on', true).first() || false;
16490 this.component = (this.component && this.component.length === 0) ? false : this.component;
16491 this.hasInput = this.component && this.inputEL().length;
16493 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16495 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16497 this.picker().on('mousedown', this.onMousedown, this);
16498 this.picker().on('click', this.onClick, this);
16500 this.picker().addClass('datepicker-dropdown');
16502 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16503 v.setStyle('width', '189px');
16510 if(this.isInline) {
16516 setValue: function(v, suppressEvent)
16518 var o = this.getValue();
16520 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16524 if(suppressEvent !== true){
16525 this.fireEvent('select', this, o, v);
16530 getValue: function()
16535 onClick: function(e)
16537 e.stopPropagation();
16538 e.preventDefault();
16540 var target = e.getTarget();
16542 if(target.nodeName.toLowerCase() === 'i'){
16543 target = Roo.get(target).dom.parentNode;
16546 var nodeName = target.nodeName;
16547 var className = target.className;
16548 var html = target.innerHTML;
16550 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16554 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16556 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16562 picker : function()
16564 return this.pickerEl;
16567 fillMonths: function()
16570 var months = this.picker().select('>.datepicker-months td', true).first();
16572 months.dom.innerHTML = '';
16578 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16581 months.createChild(month);
16590 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16591 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16594 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16595 e.removeClass('active');
16597 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16598 e.addClass('active');
16605 if(this.isInline) return;
16607 this.picker().removeClass(['bottom', 'top']);
16609 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16611 * place to the top of element!
16615 this.picker().addClass('top');
16616 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16621 this.picker().addClass('bottom');
16623 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16626 onFocus : function()
16628 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16632 onBlur : function()
16634 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16636 var d = this.inputEl().getValue();
16645 this.picker().show();
16646 this.picker().select('>.datepicker-months', true).first().show();
16650 this.fireEvent('show', this, this.date);
16655 if(this.isInline) return;
16656 this.picker().hide();
16657 this.fireEvent('hide', this, this.date);
16661 onMousedown: function(e)
16663 e.stopPropagation();
16664 e.preventDefault();
16669 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16673 fireKey: function(e)
16675 if (!this.picker().isVisible()){
16676 if (e.keyCode == 27) // allow escape to hide and re-show picker
16686 e.preventDefault();
16690 dir = e.keyCode == 37 ? -1 : 1;
16692 this.vIndex = this.vIndex + dir;
16694 if(this.vIndex < 0){
16698 if(this.vIndex > 11){
16702 if(isNaN(this.vIndex)){
16706 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16712 dir = e.keyCode == 38 ? -1 : 1;
16714 this.vIndex = this.vIndex + dir * 4;
16716 if(this.vIndex < 0){
16720 if(this.vIndex > 11){
16724 if(isNaN(this.vIndex)){
16728 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16733 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16734 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16738 e.preventDefault();
16741 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16742 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16758 this.picker().remove();
16763 Roo.apply(Roo.bootstrap.MonthField, {
16782 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16783 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16788 Roo.apply(Roo.bootstrap.MonthField, {
16792 cls: 'datepicker dropdown-menu roo-dynamic',
16796 cls: 'datepicker-months',
16800 cls: 'table-condensed',
16802 Roo.bootstrap.DateField.content
16822 * @class Roo.bootstrap.CheckBox
16823 * @extends Roo.bootstrap.Input
16824 * Bootstrap CheckBox class
16826 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16827 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16828 * @cfg {String} boxLabel The text that appears beside the checkbox
16829 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16830 * @cfg {Boolean} checked initnal the element
16831 * @cfg {Boolean} inline inline the element (default false)
16832 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16835 * Create a new CheckBox
16836 * @param {Object} config The config object
16839 Roo.bootstrap.CheckBox = function(config){
16840 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16845 * Fires when the element is checked or unchecked.
16846 * @param {Roo.bootstrap.CheckBox} this This input
16847 * @param {Boolean} checked The new checked value
16854 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16856 inputType: 'checkbox',
16864 getAutoCreate : function()
16866 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16872 cfg.cls = 'form-group ' + this.inputType; //input-group
16875 cfg.cls += ' ' + this.inputType + '-inline';
16881 type : this.inputType,
16882 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16883 cls : 'roo-' + this.inputType, //'form-box',
16884 placeholder : this.placeholder || ''
16888 if (this.weight) { // Validity check?
16889 cfg.cls += " " + this.inputType + "-" + this.weight;
16892 if (this.disabled) {
16893 input.disabled=true;
16897 input.checked = this.checked;
16901 input.name = this.name;
16905 input.cls += ' input-' + this.size;
16910 ['xs','sm','md','lg'].map(function(size){
16911 if (settings[size]) {
16912 cfg.cls += ' col-' + size + '-' + settings[size];
16916 var inputblock = input;
16918 if (this.before || this.after) {
16921 cls : 'input-group',
16926 inputblock.cn.push({
16928 cls : 'input-group-addon',
16933 inputblock.cn.push(input);
16936 inputblock.cn.push({
16938 cls : 'input-group-addon',
16945 if (align ==='left' && this.fieldLabel.length) {
16946 Roo.log("left and has label");
16952 cls : 'control-label col-md-' + this.labelWidth,
16953 html : this.fieldLabel
16957 cls : "col-md-" + (12 - this.labelWidth),
16964 } else if ( this.fieldLabel.length) {
16969 tag: this.boxLabel ? 'span' : 'label',
16971 cls: 'control-label box-input-label',
16972 //cls : 'input-group-addon',
16973 html : this.fieldLabel
16983 Roo.log(" no label && no align");
16984 cfg.cn = [ inputblock ] ;
16989 var boxLabelCfg = {
16991 //'for': id, // box label is handled by onclick - so no for...
16993 html: this.boxLabel
16997 boxLabelCfg.tooltip = this.tooltip;
17000 cfg.cn.push(boxLabelCfg);
17010 * return the real input element.
17012 inputEl: function ()
17014 return this.el.select('input.roo-' + this.inputType,true).first();
17017 labelEl: function()
17019 return this.el.select('label.control-label',true).first();
17021 /* depricated... */
17025 return this.labelEl();
17028 initEvents : function()
17030 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17032 this.inputEl().on('click', this.onClick, this);
17034 if (this.boxLabel) {
17035 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17038 this.startValue = this.getValue();
17041 Roo.bootstrap.CheckBox.register(this);
17045 onClick : function()
17047 this.setChecked(!this.checked);
17050 setChecked : function(state,suppressEvent)
17052 this.startValue = this.getValue();
17054 if(this.inputType == 'radio'){
17056 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17057 e.dom.checked = false;
17060 this.inputEl().dom.checked = true;
17062 this.inputEl().dom.value = this.inputValue;
17064 if(suppressEvent !== true){
17065 this.fireEvent('check', this, true);
17073 this.checked = state;
17075 this.inputEl().dom.checked = state;
17077 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17079 if(suppressEvent !== true){
17080 this.fireEvent('check', this, state);
17086 getValue : function()
17088 if(this.inputType == 'radio'){
17089 return this.getGroupValue();
17092 return this.inputEl().getValue();
17096 getGroupValue : function()
17098 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17102 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17105 setValue : function(v,suppressEvent)
17107 if(this.inputType == 'radio'){
17108 this.setGroupValue(v, suppressEvent);
17112 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17117 setGroupValue : function(v, suppressEvent)
17119 this.startValue = this.getValue();
17121 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17122 e.dom.checked = false;
17124 if(e.dom.value == v){
17125 e.dom.checked = true;
17129 if(suppressEvent !== true){
17130 this.fireEvent('check', this, true);
17138 validate : function()
17142 (this.inputType == 'radio' && this.validateRadio()) ||
17143 (this.inputType == 'checkbox' && this.validateCheckbox())
17149 this.markInvalid();
17153 validateRadio : function()
17157 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17158 if(!e.dom.checked){
17170 validateCheckbox : function()
17173 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17176 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17184 for(var i in group){
17189 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17196 * Mark this field as valid
17198 markValid : function()
17200 if(this.allowBlank){
17206 this.fireEvent('valid', this);
17208 if(this.inputType == 'radio'){
17209 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17210 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17211 e.findParent('.form-group', false, true).addClass(_this.validClass);
17218 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17219 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17223 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17229 for(var i in group){
17230 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17231 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17236 * Mark this field as invalid
17237 * @param {String} msg The validation message
17239 markInvalid : function(msg)
17241 if(this.allowBlank){
17247 this.fireEvent('invalid', this, msg);
17249 if(this.inputType == 'radio'){
17250 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17251 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17252 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17259 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17260 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17264 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17270 for(var i in group){
17271 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17272 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17279 Roo.apply(Roo.bootstrap.CheckBox, {
17284 * register a CheckBox Group
17285 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17287 register : function(checkbox)
17289 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17290 this.groups[checkbox.groupId] = {};
17293 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17297 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17301 * fetch a CheckBox Group based on the group ID
17302 * @param {string} the group ID
17303 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17305 get: function(groupId) {
17306 if (typeof(this.groups[groupId]) == 'undefined') {
17310 return this.groups[groupId] ;
17322 *<div class="radio">
17324 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17325 Option one is this and that—be sure to include why it's great
17332 *<label class="radio-inline">fieldLabel</label>
17333 *<label class="radio-inline">
17334 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17342 * @class Roo.bootstrap.Radio
17343 * @extends Roo.bootstrap.CheckBox
17344 * Bootstrap Radio class
17347 * Create a new Radio
17348 * @param {Object} config The config object
17351 Roo.bootstrap.Radio = function(config){
17352 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17356 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17358 inputType: 'radio',
17362 getAutoCreate : function()
17364 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17365 align = align || 'left'; // default...
17372 tag : this.inline ? 'span' : 'div',
17377 var inline = this.inline ? ' radio-inline' : '';
17381 // does not need for, as we wrap the input with it..
17383 cls : 'control-label box-label' + inline,
17386 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17390 //cls : 'control-label' + inline,
17391 html : this.fieldLabel,
17392 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17401 type : this.inputType,
17402 //value : (!this.checked) ? this.valueOff : this.inputValue,
17403 value : this.inputValue,
17405 placeholder : this.placeholder || '' // ?? needed????
17408 if (this.weight) { // Validity check?
17409 input.cls += " radio-" + this.weight;
17411 if (this.disabled) {
17412 input.disabled=true;
17416 input.checked = this.checked;
17420 input.name = this.name;
17424 input.cls += ' input-' + this.size;
17427 //?? can span's inline have a width??
17430 ['xs','sm','md','lg'].map(function(size){
17431 if (settings[size]) {
17432 cfg.cls += ' col-' + size + '-' + settings[size];
17436 var inputblock = input;
17438 if (this.before || this.after) {
17441 cls : 'input-group',
17446 inputblock.cn.push({
17448 cls : 'input-group-addon',
17452 inputblock.cn.push(input);
17454 inputblock.cn.push({
17456 cls : 'input-group-addon',
17464 if (this.fieldLabel && this.fieldLabel.length) {
17465 cfg.cn.push(fieldLabel);
17468 // normal bootstrap puts the input inside the label.
17469 // however with our styled version - it has to go after the input.
17471 //lbl.cn.push(inputblock);
17475 cls: 'radio' + inline,
17482 cfg.cn.push( lblwrap);
17487 html: this.boxLabel
17496 initEvents : function()
17498 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17500 this.inputEl().on('click', this.onClick, this);
17501 if (this.boxLabel) {
17502 Roo.log('find label')
17503 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17508 inputEl: function ()
17510 return this.el.select('input.roo-radio',true).first();
17512 onClick : function()
17515 this.setChecked(true);
17518 setChecked : function(state,suppressEvent)
17521 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17522 v.dom.checked = false;
17525 Roo.log(this.inputEl().dom);
17526 this.checked = state;
17527 this.inputEl().dom.checked = state;
17529 if(suppressEvent !== true){
17530 this.fireEvent('check', this, state);
17533 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17537 getGroupValue : function()
17540 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17541 if(v.dom.checked == true){
17542 value = v.dom.value;
17550 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17551 * @return {Mixed} value The field value
17553 getValue : function(){
17554 return this.getGroupValue();
17560 //<script type="text/javascript">
17563 * Based Ext JS Library 1.1.1
17564 * Copyright(c) 2006-2007, Ext JS, LLC.
17570 * @class Roo.HtmlEditorCore
17571 * @extends Roo.Component
17572 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17574 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17577 Roo.HtmlEditorCore = function(config){
17580 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17585 * @event initialize
17586 * Fires when the editor is fully initialized (including the iframe)
17587 * @param {Roo.HtmlEditorCore} this
17592 * Fires when the editor is first receives the focus. Any insertion must wait
17593 * until after this event.
17594 * @param {Roo.HtmlEditorCore} this
17598 * @event beforesync
17599 * Fires before the textarea is updated with content from the editor iframe. Return false
17600 * to cancel the sync.
17601 * @param {Roo.HtmlEditorCore} this
17602 * @param {String} html
17606 * @event beforepush
17607 * Fires before the iframe editor is updated with content from the textarea. Return false
17608 * to cancel the push.
17609 * @param {Roo.HtmlEditorCore} this
17610 * @param {String} html
17615 * Fires when the textarea is updated with content from the editor iframe.
17616 * @param {Roo.HtmlEditorCore} this
17617 * @param {String} html
17622 * Fires when the iframe editor is updated with content from the textarea.
17623 * @param {Roo.HtmlEditorCore} this
17624 * @param {String} html
17629 * @event editorevent
17630 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17631 * @param {Roo.HtmlEditorCore} this
17637 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17639 // defaults : white / black...
17640 this.applyBlacklists();
17647 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17651 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17657 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17662 * @cfg {Number} height (in pixels)
17666 * @cfg {Number} width (in pixels)
17671 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17674 stylesheets: false,
17679 // private properties
17680 validationEvent : false,
17682 initialized : false,
17684 sourceEditMode : false,
17685 onFocus : Roo.emptyFn,
17687 hideMode:'offsets',
17691 // blacklist + whitelisted elements..
17698 * Protected method that will not generally be called directly. It
17699 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17700 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17702 getDocMarkup : function(){
17706 // inherit styels from page...??
17707 if (this.stylesheets === false) {
17709 Roo.get(document.head).select('style').each(function(node) {
17710 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17713 Roo.get(document.head).select('link').each(function(node) {
17714 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17717 } else if (!this.stylesheets.length) {
17719 st = '<style type="text/css">' +
17720 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17726 st += '<style type="text/css">' +
17727 'IMG { cursor: pointer } ' +
17731 return '<html><head>' + st +
17732 //<style type="text/css">' +
17733 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17735 ' </head><body class="roo-htmleditor-body"></body></html>';
17739 onRender : function(ct, position)
17742 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17743 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17746 this.el.dom.style.border = '0 none';
17747 this.el.dom.setAttribute('tabIndex', -1);
17748 this.el.addClass('x-hidden hide');
17752 if(Roo.isIE){ // fix IE 1px bogus margin
17753 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17757 this.frameId = Roo.id();
17761 var iframe = this.owner.wrap.createChild({
17763 cls: 'form-control', // bootstrap..
17765 name: this.frameId,
17766 frameBorder : 'no',
17767 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17772 this.iframe = iframe.dom;
17774 this.assignDocWin();
17776 this.doc.designMode = 'on';
17779 this.doc.write(this.getDocMarkup());
17783 var task = { // must defer to wait for browser to be ready
17785 //console.log("run task?" + this.doc.readyState);
17786 this.assignDocWin();
17787 if(this.doc.body || this.doc.readyState == 'complete'){
17789 this.doc.designMode="on";
17793 Roo.TaskMgr.stop(task);
17794 this.initEditor.defer(10, this);
17801 Roo.TaskMgr.start(task);
17806 onResize : function(w, h)
17808 Roo.log('resize: ' +w + ',' + h );
17809 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17813 if(typeof w == 'number'){
17815 this.iframe.style.width = w + 'px';
17817 if(typeof h == 'number'){
17819 this.iframe.style.height = h + 'px';
17821 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17828 * Toggles the editor between standard and source edit mode.
17829 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17831 toggleSourceEdit : function(sourceEditMode){
17833 this.sourceEditMode = sourceEditMode === true;
17835 if(this.sourceEditMode){
17837 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17840 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17841 //this.iframe.className = '';
17844 //this.setSize(this.owner.wrap.getSize());
17845 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17852 * Protected method that will not generally be called directly. If you need/want
17853 * custom HTML cleanup, this is the method you should override.
17854 * @param {String} html The HTML to be cleaned
17855 * return {String} The cleaned HTML
17857 cleanHtml : function(html){
17858 html = String(html);
17859 if(html.length > 5){
17860 if(Roo.isSafari){ // strip safari nonsense
17861 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17864 if(html == ' '){
17871 * HTML Editor -> Textarea
17872 * Protected method that will not generally be called directly. Syncs the contents
17873 * of the editor iframe with the textarea.
17875 syncValue : function(){
17876 if(this.initialized){
17877 var bd = (this.doc.body || this.doc.documentElement);
17878 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17879 var html = bd.innerHTML;
17881 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17882 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17884 html = '<div style="'+m[0]+'">' + html + '</div>';
17887 html = this.cleanHtml(html);
17888 // fix up the special chars.. normaly like back quotes in word...
17889 // however we do not want to do this with chinese..
17890 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17891 var cc = b.charCodeAt();
17893 (cc >= 0x4E00 && cc < 0xA000 ) ||
17894 (cc >= 0x3400 && cc < 0x4E00 ) ||
17895 (cc >= 0xf900 && cc < 0xfb00 )
17901 if(this.owner.fireEvent('beforesync', this, html) !== false){
17902 this.el.dom.value = html;
17903 this.owner.fireEvent('sync', this, html);
17909 * Protected method that will not generally be called directly. Pushes the value of the textarea
17910 * into the iframe editor.
17912 pushValue : function(){
17913 if(this.initialized){
17914 var v = this.el.dom.value.trim();
17916 // if(v.length < 1){
17920 if(this.owner.fireEvent('beforepush', this, v) !== false){
17921 var d = (this.doc.body || this.doc.documentElement);
17923 this.cleanUpPaste();
17924 this.el.dom.value = d.innerHTML;
17925 this.owner.fireEvent('push', this, v);
17931 deferFocus : function(){
17932 this.focus.defer(10, this);
17936 focus : function(){
17937 if(this.win && !this.sourceEditMode){
17944 assignDocWin: function()
17946 var iframe = this.iframe;
17949 this.doc = iframe.contentWindow.document;
17950 this.win = iframe.contentWindow;
17952 // if (!Roo.get(this.frameId)) {
17955 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17956 // this.win = Roo.get(this.frameId).dom.contentWindow;
17958 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17962 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17963 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17968 initEditor : function(){
17969 //console.log("INIT EDITOR");
17970 this.assignDocWin();
17974 this.doc.designMode="on";
17976 this.doc.write(this.getDocMarkup());
17979 var dbody = (this.doc.body || this.doc.documentElement);
17980 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17981 // this copies styles from the containing element into thsi one..
17982 // not sure why we need all of this..
17983 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17985 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17986 //ss['background-attachment'] = 'fixed'; // w3c
17987 dbody.bgProperties = 'fixed'; // ie
17988 //Roo.DomHelper.applyStyles(dbody, ss);
17989 Roo.EventManager.on(this.doc, {
17990 //'mousedown': this.onEditorEvent,
17991 'mouseup': this.onEditorEvent,
17992 'dblclick': this.onEditorEvent,
17993 'click': this.onEditorEvent,
17994 'keyup': this.onEditorEvent,
17999 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18001 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18002 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18004 this.initialized = true;
18006 this.owner.fireEvent('initialize', this);
18011 onDestroy : function(){
18017 //for (var i =0; i < this.toolbars.length;i++) {
18018 // // fixme - ask toolbars for heights?
18019 // this.toolbars[i].onDestroy();
18022 //this.wrap.dom.innerHTML = '';
18023 //this.wrap.remove();
18028 onFirstFocus : function(){
18030 this.assignDocWin();
18033 this.activated = true;
18036 if(Roo.isGecko){ // prevent silly gecko errors
18038 var s = this.win.getSelection();
18039 if(!s.focusNode || s.focusNode.nodeType != 3){
18040 var r = s.getRangeAt(0);
18041 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18046 this.execCmd('useCSS', true);
18047 this.execCmd('styleWithCSS', false);
18050 this.owner.fireEvent('activate', this);
18054 adjustFont: function(btn){
18055 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18056 //if(Roo.isSafari){ // safari
18059 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18060 if(Roo.isSafari){ // safari
18061 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18062 v = (v < 10) ? 10 : v;
18063 v = (v > 48) ? 48 : v;
18064 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18069 v = Math.max(1, v+adjust);
18071 this.execCmd('FontSize', v );
18074 onEditorEvent : function(e){
18075 this.owner.fireEvent('editorevent', this, e);
18076 // this.updateToolbar();
18077 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18080 insertTag : function(tg)
18082 // could be a bit smarter... -> wrap the current selected tRoo..
18083 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18085 range = this.createRange(this.getSelection());
18086 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18087 wrappingNode.appendChild(range.extractContents());
18088 range.insertNode(wrappingNode);
18095 this.execCmd("formatblock", tg);
18099 insertText : function(txt)
18103 var range = this.createRange();
18104 range.deleteContents();
18105 //alert(Sender.getAttribute('label'));
18107 range.insertNode(this.doc.createTextNode(txt));
18113 * Executes a Midas editor command on the editor document and performs necessary focus and
18114 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18115 * @param {String} cmd The Midas command
18116 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18118 relayCmd : function(cmd, value){
18120 this.execCmd(cmd, value);
18121 this.owner.fireEvent('editorevent', this);
18122 //this.updateToolbar();
18123 this.owner.deferFocus();
18127 * Executes a Midas editor command directly on the editor document.
18128 * For visual commands, you should use {@link #relayCmd} instead.
18129 * <b>This should only be called after the editor is initialized.</b>
18130 * @param {String} cmd The Midas command
18131 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18133 execCmd : function(cmd, value){
18134 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18141 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18143 * @param {String} text | dom node..
18145 insertAtCursor : function(text)
18150 if(!this.activated){
18156 var r = this.doc.selection.createRange();
18167 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18171 // from jquery ui (MIT licenced)
18173 var win = this.win;
18175 if (win.getSelection && win.getSelection().getRangeAt) {
18176 range = win.getSelection().getRangeAt(0);
18177 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18178 range.insertNode(node);
18179 } else if (win.document.selection && win.document.selection.createRange) {
18180 // no firefox support
18181 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18182 win.document.selection.createRange().pasteHTML(txt);
18184 // no firefox support
18185 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18186 this.execCmd('InsertHTML', txt);
18195 mozKeyPress : function(e){
18197 var c = e.getCharCode(), cmd;
18200 c = String.fromCharCode(c).toLowerCase();
18214 this.cleanUpPaste.defer(100, this);
18222 e.preventDefault();
18230 fixKeys : function(){ // load time branching for fastest keydown performance
18232 return function(e){
18233 var k = e.getKey(), r;
18236 r = this.doc.selection.createRange();
18239 r.pasteHTML('    ');
18246 r = this.doc.selection.createRange();
18248 var target = r.parentElement();
18249 if(!target || target.tagName.toLowerCase() != 'li'){
18251 r.pasteHTML('<br />');
18257 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18258 this.cleanUpPaste.defer(100, this);
18264 }else if(Roo.isOpera){
18265 return function(e){
18266 var k = e.getKey();
18270 this.execCmd('InsertHTML','    ');
18273 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18274 this.cleanUpPaste.defer(100, this);
18279 }else if(Roo.isSafari){
18280 return function(e){
18281 var k = e.getKey();
18285 this.execCmd('InsertText','\t');
18289 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18290 this.cleanUpPaste.defer(100, this);
18298 getAllAncestors: function()
18300 var p = this.getSelectedNode();
18303 a.push(p); // push blank onto stack..
18304 p = this.getParentElement();
18308 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18312 a.push(this.doc.body);
18316 lastSelNode : false,
18319 getSelection : function()
18321 this.assignDocWin();
18322 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18325 getSelectedNode: function()
18327 // this may only work on Gecko!!!
18329 // should we cache this!!!!
18334 var range = this.createRange(this.getSelection()).cloneRange();
18337 var parent = range.parentElement();
18339 var testRange = range.duplicate();
18340 testRange.moveToElementText(parent);
18341 if (testRange.inRange(range)) {
18344 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18347 parent = parent.parentElement;
18352 // is ancestor a text element.
18353 var ac = range.commonAncestorContainer;
18354 if (ac.nodeType == 3) {
18355 ac = ac.parentNode;
18358 var ar = ac.childNodes;
18361 var other_nodes = [];
18362 var has_other_nodes = false;
18363 for (var i=0;i<ar.length;i++) {
18364 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18367 // fullly contained node.
18369 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18374 // probably selected..
18375 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18376 other_nodes.push(ar[i]);
18380 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18385 has_other_nodes = true;
18387 if (!nodes.length && other_nodes.length) {
18388 nodes= other_nodes;
18390 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18396 createRange: function(sel)
18398 // this has strange effects when using with
18399 // top toolbar - not sure if it's a great idea.
18400 //this.editor.contentWindow.focus();
18401 if (typeof sel != "undefined") {
18403 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18405 return this.doc.createRange();
18408 return this.doc.createRange();
18411 getParentElement: function()
18414 this.assignDocWin();
18415 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18417 var range = this.createRange(sel);
18420 var p = range.commonAncestorContainer;
18421 while (p.nodeType == 3) { // text node
18432 * Range intersection.. the hard stuff...
18436 * [ -- selected range --- ]
18440 * if end is before start or hits it. fail.
18441 * if start is after end or hits it fail.
18443 * if either hits (but other is outside. - then it's not
18449 // @see http://www.thismuchiknow.co.uk/?p=64.
18450 rangeIntersectsNode : function(range, node)
18452 var nodeRange = node.ownerDocument.createRange();
18454 nodeRange.selectNode(node);
18456 nodeRange.selectNodeContents(node);
18459 var rangeStartRange = range.cloneRange();
18460 rangeStartRange.collapse(true);
18462 var rangeEndRange = range.cloneRange();
18463 rangeEndRange.collapse(false);
18465 var nodeStartRange = nodeRange.cloneRange();
18466 nodeStartRange.collapse(true);
18468 var nodeEndRange = nodeRange.cloneRange();
18469 nodeEndRange.collapse(false);
18471 return rangeStartRange.compareBoundaryPoints(
18472 Range.START_TO_START, nodeEndRange) == -1 &&
18473 rangeEndRange.compareBoundaryPoints(
18474 Range.START_TO_START, nodeStartRange) == 1;
18478 rangeCompareNode : function(range, node)
18480 var nodeRange = node.ownerDocument.createRange();
18482 nodeRange.selectNode(node);
18484 nodeRange.selectNodeContents(node);
18488 range.collapse(true);
18490 nodeRange.collapse(true);
18492 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18493 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18495 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18497 var nodeIsBefore = ss == 1;
18498 var nodeIsAfter = ee == -1;
18500 if (nodeIsBefore && nodeIsAfter)
18502 if (!nodeIsBefore && nodeIsAfter)
18503 return 1; //right trailed.
18505 if (nodeIsBefore && !nodeIsAfter)
18506 return 2; // left trailed.
18511 // private? - in a new class?
18512 cleanUpPaste : function()
18514 // cleans up the whole document..
18515 Roo.log('cleanuppaste');
18517 this.cleanUpChildren(this.doc.body);
18518 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18519 if (clean != this.doc.body.innerHTML) {
18520 this.doc.body.innerHTML = clean;
18525 cleanWordChars : function(input) {// change the chars to hex code
18526 var he = Roo.HtmlEditorCore;
18528 var output = input;
18529 Roo.each(he.swapCodes, function(sw) {
18530 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18532 output = output.replace(swapper, sw[1]);
18539 cleanUpChildren : function (n)
18541 if (!n.childNodes.length) {
18544 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18545 this.cleanUpChild(n.childNodes[i]);
18552 cleanUpChild : function (node)
18555 //console.log(node);
18556 if (node.nodeName == "#text") {
18557 // clean up silly Windows -- stuff?
18560 if (node.nodeName == "#comment") {
18561 node.parentNode.removeChild(node);
18562 // clean up silly Windows -- stuff?
18565 var lcname = node.tagName.toLowerCase();
18566 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18567 // whitelist of tags..
18569 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18571 node.parentNode.removeChild(node);
18576 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18578 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18579 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18581 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18582 // remove_keep_children = true;
18585 if (remove_keep_children) {
18586 this.cleanUpChildren(node);
18587 // inserts everything just before this node...
18588 while (node.childNodes.length) {
18589 var cn = node.childNodes[0];
18590 node.removeChild(cn);
18591 node.parentNode.insertBefore(cn, node);
18593 node.parentNode.removeChild(node);
18597 if (!node.attributes || !node.attributes.length) {
18598 this.cleanUpChildren(node);
18602 function cleanAttr(n,v)
18605 if (v.match(/^\./) || v.match(/^\//)) {
18608 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18611 if (v.match(/^#/)) {
18614 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18615 node.removeAttribute(n);
18619 var cwhite = this.cwhite;
18620 var cblack = this.cblack;
18622 function cleanStyle(n,v)
18624 if (v.match(/expression/)) { //XSS?? should we even bother..
18625 node.removeAttribute(n);
18629 var parts = v.split(/;/);
18632 Roo.each(parts, function(p) {
18633 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18637 var l = p.split(':').shift().replace(/\s+/g,'');
18638 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18640 if ( cwhite.length && cblack.indexOf(l) > -1) {
18641 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18642 //node.removeAttribute(n);
18646 // only allow 'c whitelisted system attributes'
18647 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18648 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18649 //node.removeAttribute(n);
18659 if (clean.length) {
18660 node.setAttribute(n, clean.join(';'));
18662 node.removeAttribute(n);
18668 for (var i = node.attributes.length-1; i > -1 ; i--) {
18669 var a = node.attributes[i];
18672 if (a.name.toLowerCase().substr(0,2)=='on') {
18673 node.removeAttribute(a.name);
18676 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18677 node.removeAttribute(a.name);
18680 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18681 cleanAttr(a.name,a.value); // fixme..
18684 if (a.name == 'style') {
18685 cleanStyle(a.name,a.value);
18688 /// clean up MS crap..
18689 // tecnically this should be a list of valid class'es..
18692 if (a.name == 'class') {
18693 if (a.value.match(/^Mso/)) {
18694 node.className = '';
18697 if (a.value.match(/body/)) {
18698 node.className = '';
18709 this.cleanUpChildren(node);
18714 * Clean up MS wordisms...
18716 cleanWord : function(node)
18719 var cleanWordChildren = function()
18721 if (!node.childNodes.length) {
18724 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18725 _t.cleanWord(node.childNodes[i]);
18731 this.cleanWord(this.doc.body);
18734 if (node.nodeName == "#text") {
18735 // clean up silly Windows -- stuff?
18738 if (node.nodeName == "#comment") {
18739 node.parentNode.removeChild(node);
18740 // clean up silly Windows -- stuff?
18744 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18745 node.parentNode.removeChild(node);
18749 // remove - but keep children..
18750 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18751 while (node.childNodes.length) {
18752 var cn = node.childNodes[0];
18753 node.removeChild(cn);
18754 node.parentNode.insertBefore(cn, node);
18756 node.parentNode.removeChild(node);
18757 cleanWordChildren();
18761 if (node.className.length) {
18763 var cn = node.className.split(/\W+/);
18765 Roo.each(cn, function(cls) {
18766 if (cls.match(/Mso[a-zA-Z]+/)) {
18771 node.className = cna.length ? cna.join(' ') : '';
18773 node.removeAttribute("class");
18777 if (node.hasAttribute("lang")) {
18778 node.removeAttribute("lang");
18781 if (node.hasAttribute("style")) {
18783 var styles = node.getAttribute("style").split(";");
18785 Roo.each(styles, function(s) {
18786 if (!s.match(/:/)) {
18789 var kv = s.split(":");
18790 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18793 // what ever is left... we allow.
18796 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18797 if (!nstyle.length) {
18798 node.removeAttribute('style');
18802 cleanWordChildren();
18806 domToHTML : function(currentElement, depth, nopadtext) {
18808 depth = depth || 0;
18809 nopadtext = nopadtext || false;
18811 if (!currentElement) {
18812 return this.domToHTML(this.doc.body);
18815 //Roo.log(currentElement);
18817 var allText = false;
18818 var nodeName = currentElement.nodeName;
18819 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18821 if (nodeName == '#text') {
18823 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18828 if (nodeName != 'BODY') {
18831 // Prints the node tagName, such as <A>, <IMG>, etc
18834 for(i = 0; i < currentElement.attributes.length;i++) {
18836 var aname = currentElement.attributes.item(i).name;
18837 if (!currentElement.attributes.item(i).value.length) {
18840 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18843 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18852 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18855 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18860 // Traverse the tree
18862 var currentElementChild = currentElement.childNodes.item(i);
18863 var allText = true;
18864 var innerHTML = '';
18866 while (currentElementChild) {
18867 // Formatting code (indent the tree so it looks nice on the screen)
18868 var nopad = nopadtext;
18869 if (lastnode == 'SPAN') {
18873 if (currentElementChild.nodeName == '#text') {
18874 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18875 toadd = nopadtext ? toadd : toadd.trim();
18876 if (!nopad && toadd.length > 80) {
18877 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18879 innerHTML += toadd;
18882 currentElementChild = currentElement.childNodes.item(i);
18888 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18890 // Recursively traverse the tree structure of the child node
18891 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18892 lastnode = currentElementChild.nodeName;
18894 currentElementChild=currentElement.childNodes.item(i);
18900 // The remaining code is mostly for formatting the tree
18901 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18906 ret+= "</"+tagName+">";
18912 applyBlacklists : function()
18914 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18915 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18919 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18920 if (b.indexOf(tag) > -1) {
18923 this.white.push(tag);
18927 Roo.each(w, function(tag) {
18928 if (b.indexOf(tag) > -1) {
18931 if (this.white.indexOf(tag) > -1) {
18934 this.white.push(tag);
18939 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18940 if (w.indexOf(tag) > -1) {
18943 this.black.push(tag);
18947 Roo.each(b, function(tag) {
18948 if (w.indexOf(tag) > -1) {
18951 if (this.black.indexOf(tag) > -1) {
18954 this.black.push(tag);
18959 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18960 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18964 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18965 if (b.indexOf(tag) > -1) {
18968 this.cwhite.push(tag);
18972 Roo.each(w, function(tag) {
18973 if (b.indexOf(tag) > -1) {
18976 if (this.cwhite.indexOf(tag) > -1) {
18979 this.cwhite.push(tag);
18984 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18985 if (w.indexOf(tag) > -1) {
18988 this.cblack.push(tag);
18992 Roo.each(b, function(tag) {
18993 if (w.indexOf(tag) > -1) {
18996 if (this.cblack.indexOf(tag) > -1) {
18999 this.cblack.push(tag);
19004 setStylesheets : function(stylesheets)
19006 if(typeof(stylesheets) == 'string'){
19007 Roo.get(this.iframe.contentDocument.head).createChild({
19009 rel : 'stylesheet',
19018 Roo.each(stylesheets, function(s) {
19023 Roo.get(_this.iframe.contentDocument.head).createChild({
19025 rel : 'stylesheet',
19034 removeStylesheets : function()
19038 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19043 // hide stuff that is not compatible
19057 * @event specialkey
19061 * @cfg {String} fieldClass @hide
19064 * @cfg {String} focusClass @hide
19067 * @cfg {String} autoCreate @hide
19070 * @cfg {String} inputType @hide
19073 * @cfg {String} invalidClass @hide
19076 * @cfg {String} invalidText @hide
19079 * @cfg {String} msgFx @hide
19082 * @cfg {String} validateOnBlur @hide
19086 Roo.HtmlEditorCore.white = [
19087 'area', 'br', 'img', 'input', 'hr', 'wbr',
19089 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19090 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19091 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19092 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19093 'table', 'ul', 'xmp',
19095 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19098 'dir', 'menu', 'ol', 'ul', 'dl',
19104 Roo.HtmlEditorCore.black = [
19105 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19107 'base', 'basefont', 'bgsound', 'blink', 'body',
19108 'frame', 'frameset', 'head', 'html', 'ilayer',
19109 'iframe', 'layer', 'link', 'meta', 'object',
19110 'script', 'style' ,'title', 'xml' // clean later..
19112 Roo.HtmlEditorCore.clean = [
19113 'script', 'style', 'title', 'xml'
19115 Roo.HtmlEditorCore.remove = [
19120 Roo.HtmlEditorCore.ablack = [
19124 Roo.HtmlEditorCore.aclean = [
19125 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19129 Roo.HtmlEditorCore.pwhite= [
19130 'http', 'https', 'mailto'
19133 // white listed style attributes.
19134 Roo.HtmlEditorCore.cwhite= [
19135 // 'text-align', /// default is to allow most things..
19141 // black listed style attributes.
19142 Roo.HtmlEditorCore.cblack= [
19143 // 'font-size' -- this can be set by the project
19147 Roo.HtmlEditorCore.swapCodes =[
19166 * @class Roo.bootstrap.HtmlEditor
19167 * @extends Roo.bootstrap.TextArea
19168 * Bootstrap HtmlEditor class
19171 * Create a new HtmlEditor
19172 * @param {Object} config The config object
19175 Roo.bootstrap.HtmlEditor = function(config){
19176 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19177 if (!this.toolbars) {
19178 this.toolbars = [];
19180 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19183 * @event initialize
19184 * Fires when the editor is fully initialized (including the iframe)
19185 * @param {HtmlEditor} this
19190 * Fires when the editor is first receives the focus. Any insertion must wait
19191 * until after this event.
19192 * @param {HtmlEditor} this
19196 * @event beforesync
19197 * Fires before the textarea is updated with content from the editor iframe. Return false
19198 * to cancel the sync.
19199 * @param {HtmlEditor} this
19200 * @param {String} html
19204 * @event beforepush
19205 * Fires before the iframe editor is updated with content from the textarea. Return false
19206 * to cancel the push.
19207 * @param {HtmlEditor} this
19208 * @param {String} html
19213 * Fires when the textarea is updated with content from the editor iframe.
19214 * @param {HtmlEditor} this
19215 * @param {String} html
19220 * Fires when the iframe editor is updated with content from the textarea.
19221 * @param {HtmlEditor} this
19222 * @param {String} html
19226 * @event editmodechange
19227 * Fires when the editor switches edit modes
19228 * @param {HtmlEditor} this
19229 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19231 editmodechange: true,
19233 * @event editorevent
19234 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19235 * @param {HtmlEditor} this
19239 * @event firstfocus
19240 * Fires when on first focus - needed by toolbars..
19241 * @param {HtmlEditor} this
19246 * Auto save the htmlEditor value as a file into Events
19247 * @param {HtmlEditor} this
19251 * @event savedpreview
19252 * preview the saved version of htmlEditor
19253 * @param {HtmlEditor} this
19260 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19264 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19269 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19274 * @cfg {Number} height (in pixels)
19278 * @cfg {Number} width (in pixels)
19283 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19286 stylesheets: false,
19291 // private properties
19292 validationEvent : false,
19294 initialized : false,
19297 onFocus : Roo.emptyFn,
19299 hideMode:'offsets',
19302 tbContainer : false,
19304 toolbarContainer :function() {
19305 return this.wrap.select('.x-html-editor-tb',true).first();
19309 * Protected method that will not generally be called directly. It
19310 * is called when the editor creates its toolbar. Override this method if you need to
19311 * add custom toolbar buttons.
19312 * @param {HtmlEditor} editor
19314 createToolbar : function(){
19316 Roo.log("create toolbars");
19318 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19319 this.toolbars[0].render(this.toolbarContainer());
19323 // if (!editor.toolbars || !editor.toolbars.length) {
19324 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19327 // for (var i =0 ; i < editor.toolbars.length;i++) {
19328 // editor.toolbars[i] = Roo.factory(
19329 // typeof(editor.toolbars[i]) == 'string' ?
19330 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19331 // Roo.bootstrap.HtmlEditor);
19332 // editor.toolbars[i].init(editor);
19338 onRender : function(ct, position)
19340 // Roo.log("Call onRender: " + this.xtype);
19342 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19344 this.wrap = this.inputEl().wrap({
19345 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19348 this.editorcore.onRender(ct, position);
19350 if (this.resizable) {
19351 this.resizeEl = new Roo.Resizable(this.wrap, {
19355 minHeight : this.height,
19356 height: this.height,
19357 handles : this.resizable,
19360 resize : function(r, w, h) {
19361 _t.onResize(w,h); // -something
19367 this.createToolbar(this);
19370 if(!this.width && this.resizable){
19371 this.setSize(this.wrap.getSize());
19373 if (this.resizeEl) {
19374 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19375 // should trigger onReize..
19381 onResize : function(w, h)
19383 Roo.log('resize: ' +w + ',' + h );
19384 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19388 if(this.inputEl() ){
19389 if(typeof w == 'number'){
19390 var aw = w - this.wrap.getFrameWidth('lr');
19391 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19394 if(typeof h == 'number'){
19395 var tbh = -11; // fixme it needs to tool bar size!
19396 for (var i =0; i < this.toolbars.length;i++) {
19397 // fixme - ask toolbars for heights?
19398 tbh += this.toolbars[i].el.getHeight();
19399 //if (this.toolbars[i].footer) {
19400 // tbh += this.toolbars[i].footer.el.getHeight();
19408 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19409 ah -= 5; // knock a few pixes off for look..
19410 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19414 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19415 this.editorcore.onResize(ew,eh);
19420 * Toggles the editor between standard and source edit mode.
19421 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19423 toggleSourceEdit : function(sourceEditMode)
19425 this.editorcore.toggleSourceEdit(sourceEditMode);
19427 if(this.editorcore.sourceEditMode){
19428 Roo.log('editor - showing textarea');
19431 // Roo.log(this.syncValue());
19433 this.inputEl().removeClass(['hide', 'x-hidden']);
19434 this.inputEl().dom.removeAttribute('tabIndex');
19435 this.inputEl().focus();
19437 Roo.log('editor - hiding textarea');
19439 // Roo.log(this.pushValue());
19442 this.inputEl().addClass(['hide', 'x-hidden']);
19443 this.inputEl().dom.setAttribute('tabIndex', -1);
19444 //this.deferFocus();
19447 if(this.resizable){
19448 this.setSize(this.wrap.getSize());
19451 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19454 // private (for BoxComponent)
19455 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19457 // private (for BoxComponent)
19458 getResizeEl : function(){
19462 // private (for BoxComponent)
19463 getPositionEl : function(){
19468 initEvents : function(){
19469 this.originalValue = this.getValue();
19473 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19476 // markInvalid : Roo.emptyFn,
19478 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19481 // clearInvalid : Roo.emptyFn,
19483 setValue : function(v){
19484 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19485 this.editorcore.pushValue();
19490 deferFocus : function(){
19491 this.focus.defer(10, this);
19495 focus : function(){
19496 this.editorcore.focus();
19502 onDestroy : function(){
19508 for (var i =0; i < this.toolbars.length;i++) {
19509 // fixme - ask toolbars for heights?
19510 this.toolbars[i].onDestroy();
19513 this.wrap.dom.innerHTML = '';
19514 this.wrap.remove();
19519 onFirstFocus : function(){
19520 //Roo.log("onFirstFocus");
19521 this.editorcore.onFirstFocus();
19522 for (var i =0; i < this.toolbars.length;i++) {
19523 this.toolbars[i].onFirstFocus();
19529 syncValue : function()
19531 this.editorcore.syncValue();
19534 pushValue : function()
19536 this.editorcore.pushValue();
19540 // hide stuff that is not compatible
19554 * @event specialkey
19558 * @cfg {String} fieldClass @hide
19561 * @cfg {String} focusClass @hide
19564 * @cfg {String} autoCreate @hide
19567 * @cfg {String} inputType @hide
19570 * @cfg {String} invalidClass @hide
19573 * @cfg {String} invalidText @hide
19576 * @cfg {String} msgFx @hide
19579 * @cfg {String} validateOnBlur @hide
19588 Roo.namespace('Roo.bootstrap.htmleditor');
19590 * @class Roo.bootstrap.HtmlEditorToolbar1
19595 new Roo.bootstrap.HtmlEditor({
19598 new Roo.bootstrap.HtmlEditorToolbar1({
19599 disable : { fonts: 1 , format: 1, ..., ... , ...],
19605 * @cfg {Object} disable List of elements to disable..
19606 * @cfg {Array} btns List of additional buttons.
19610 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19613 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19616 Roo.apply(this, config);
19618 // default disabled, based on 'good practice'..
19619 this.disable = this.disable || {};
19620 Roo.applyIf(this.disable, {
19623 specialElements : true
19625 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19627 this.editor = config.editor;
19628 this.editorcore = config.editor.editorcore;
19630 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19632 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19633 // dont call parent... till later.
19635 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19640 editorcore : false,
19645 "h1","h2","h3","h4","h5","h6",
19647 "abbr", "acronym", "address", "cite", "samp", "var",
19651 onRender : function(ct, position)
19653 // Roo.log("Call onRender: " + this.xtype);
19655 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19657 this.el.dom.style.marginBottom = '0';
19659 var editorcore = this.editorcore;
19660 var editor= this.editor;
19663 var btn = function(id,cmd , toggle, handler){
19665 var event = toggle ? 'toggle' : 'click';
19670 xns: Roo.bootstrap,
19673 enableToggle:toggle !== false,
19675 pressed : toggle ? false : null,
19678 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19679 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19688 xns: Roo.bootstrap,
19689 glyphicon : 'font',
19693 xns: Roo.bootstrap,
19697 Roo.each(this.formats, function(f) {
19698 style.menu.items.push({
19700 xns: Roo.bootstrap,
19701 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19706 editorcore.insertTag(this.tagname);
19713 children.push(style);
19716 btn('bold',false,true);
19717 btn('italic',false,true);
19718 btn('align-left', 'justifyleft',true);
19719 btn('align-center', 'justifycenter',true);
19720 btn('align-right' , 'justifyright',true);
19721 btn('link', false, false, function(btn) {
19722 //Roo.log("create link?");
19723 var url = prompt(this.createLinkText, this.defaultLinkValue);
19724 if(url && url != 'http:/'+'/'){
19725 this.editorcore.relayCmd('createlink', url);
19728 btn('list','insertunorderedlist',true);
19729 btn('pencil', false,true, function(btn){
19732 this.toggleSourceEdit(btn.pressed);
19738 xns: Roo.bootstrap,
19743 xns: Roo.bootstrap,
19748 cog.menu.items.push({
19750 xns: Roo.bootstrap,
19751 html : Clean styles,
19756 editorcore.insertTag(this.tagname);
19765 this.xtype = 'NavSimplebar';
19767 for(var i=0;i< children.length;i++) {
19769 this.buttons.add(this.addxtypeChild(children[i]));
19773 editor.on('editorevent', this.updateToolbar, this);
19775 onBtnClick : function(id)
19777 this.editorcore.relayCmd(id);
19778 this.editorcore.focus();
19782 * Protected method that will not generally be called directly. It triggers
19783 * a toolbar update by reading the markup state of the current selection in the editor.
19785 updateToolbar: function(){
19787 if(!this.editorcore.activated){
19788 this.editor.onFirstFocus(); // is this neeed?
19792 var btns = this.buttons;
19793 var doc = this.editorcore.doc;
19794 btns.get('bold').setActive(doc.queryCommandState('bold'));
19795 btns.get('italic').setActive(doc.queryCommandState('italic'));
19796 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19798 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19799 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19800 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19802 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19803 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19806 var ans = this.editorcore.getAllAncestors();
19807 if (this.formatCombo) {
19810 var store = this.formatCombo.store;
19811 this.formatCombo.setValue("");
19812 for (var i =0; i < ans.length;i++) {
19813 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19815 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19823 // hides menus... - so this cant be on a menu...
19824 Roo.bootstrap.MenuMgr.hideAll();
19826 Roo.bootstrap.MenuMgr.hideAll();
19827 //this.editorsyncValue();
19829 onFirstFocus: function() {
19830 this.buttons.each(function(item){
19834 toggleSourceEdit : function(sourceEditMode){
19837 if(sourceEditMode){
19838 Roo.log("disabling buttons");
19839 this.buttons.each( function(item){
19840 if(item.cmd != 'pencil'){
19846 Roo.log("enabling buttons");
19847 if(this.editorcore.initialized){
19848 this.buttons.each( function(item){
19854 Roo.log("calling toggole on editor");
19855 // tell the editor that it's been pressed..
19856 this.editor.toggleSourceEdit(sourceEditMode);
19866 * @class Roo.bootstrap.Table.AbstractSelectionModel
19867 * @extends Roo.util.Observable
19868 * Abstract base class for grid SelectionModels. It provides the interface that should be
19869 * implemented by descendant classes. This class should not be directly instantiated.
19872 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19873 this.locked = false;
19874 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19878 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19879 /** @ignore Called by the grid automatically. Do not call directly. */
19880 init : function(grid){
19886 * Locks the selections.
19889 this.locked = true;
19893 * Unlocks the selections.
19895 unlock : function(){
19896 this.locked = false;
19900 * Returns true if the selections are locked.
19901 * @return {Boolean}
19903 isLocked : function(){
19904 return this.locked;
19908 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19909 * @class Roo.bootstrap.Table.RowSelectionModel
19910 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19911 * It supports multiple selections and keyboard selection/navigation.
19913 * @param {Object} config
19916 Roo.bootstrap.Table.RowSelectionModel = function(config){
19917 Roo.apply(this, config);
19918 this.selections = new Roo.util.MixedCollection(false, function(o){
19923 this.lastActive = false;
19927 * @event selectionchange
19928 * Fires when the selection changes
19929 * @param {SelectionModel} this
19931 "selectionchange" : true,
19933 * @event afterselectionchange
19934 * Fires after the selection changes (eg. by key press or clicking)
19935 * @param {SelectionModel} this
19937 "afterselectionchange" : true,
19939 * @event beforerowselect
19940 * Fires when a row is selected being selected, return false to cancel.
19941 * @param {SelectionModel} this
19942 * @param {Number} rowIndex The selected index
19943 * @param {Boolean} keepExisting False if other selections will be cleared
19945 "beforerowselect" : true,
19948 * Fires when a row is selected.
19949 * @param {SelectionModel} this
19950 * @param {Number} rowIndex The selected index
19951 * @param {Roo.data.Record} r The record
19953 "rowselect" : true,
19955 * @event rowdeselect
19956 * Fires when a row is deselected.
19957 * @param {SelectionModel} this
19958 * @param {Number} rowIndex The selected index
19960 "rowdeselect" : true
19962 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19963 this.locked = false;
19966 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19968 * @cfg {Boolean} singleSelect
19969 * True to allow selection of only one row at a time (defaults to false)
19971 singleSelect : false,
19974 initEvents : function(){
19976 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19977 this.grid.on("mousedown", this.handleMouseDown, this);
19978 }else{ // allow click to work like normal
19979 this.grid.on("rowclick", this.handleDragableRowClick, this);
19982 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19983 "up" : function(e){
19985 this.selectPrevious(e.shiftKey);
19986 }else if(this.last !== false && this.lastActive !== false){
19987 var last = this.last;
19988 this.selectRange(this.last, this.lastActive-1);
19989 this.grid.getView().focusRow(this.lastActive);
19990 if(last !== false){
19994 this.selectFirstRow();
19996 this.fireEvent("afterselectionchange", this);
19998 "down" : function(e){
20000 this.selectNext(e.shiftKey);
20001 }else if(this.last !== false && this.lastActive !== false){
20002 var last = this.last;
20003 this.selectRange(this.last, this.lastActive+1);
20004 this.grid.getView().focusRow(this.lastActive);
20005 if(last !== false){
20009 this.selectFirstRow();
20011 this.fireEvent("afterselectionchange", this);
20016 var view = this.grid.view;
20017 view.on("refresh", this.onRefresh, this);
20018 view.on("rowupdated", this.onRowUpdated, this);
20019 view.on("rowremoved", this.onRemove, this);
20023 onRefresh : function(){
20024 var ds = this.grid.dataSource, i, v = this.grid.view;
20025 var s = this.selections;
20026 s.each(function(r){
20027 if((i = ds.indexOfId(r.id)) != -1){
20036 onRemove : function(v, index, r){
20037 this.selections.remove(r);
20041 onRowUpdated : function(v, index, r){
20042 if(this.isSelected(r)){
20043 v.onRowSelect(index);
20049 * @param {Array} records The records to select
20050 * @param {Boolean} keepExisting (optional) True to keep existing selections
20052 selectRecords : function(records, keepExisting){
20054 this.clearSelections();
20056 var ds = this.grid.dataSource;
20057 for(var i = 0, len = records.length; i < len; i++){
20058 this.selectRow(ds.indexOf(records[i]), true);
20063 * Gets the number of selected rows.
20066 getCount : function(){
20067 return this.selections.length;
20071 * Selects the first row in the grid.
20073 selectFirstRow : function(){
20078 * Select the last row.
20079 * @param {Boolean} keepExisting (optional) True to keep existing selections
20081 selectLastRow : function(keepExisting){
20082 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20086 * Selects the row immediately following the last selected row.
20087 * @param {Boolean} keepExisting (optional) True to keep existing selections
20089 selectNext : function(keepExisting){
20090 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20091 this.selectRow(this.last+1, keepExisting);
20092 this.grid.getView().focusRow(this.last);
20097 * Selects the row that precedes the last selected row.
20098 * @param {Boolean} keepExisting (optional) True to keep existing selections
20100 selectPrevious : function(keepExisting){
20102 this.selectRow(this.last-1, keepExisting);
20103 this.grid.getView().focusRow(this.last);
20108 * Returns the selected records
20109 * @return {Array} Array of selected records
20111 getSelections : function(){
20112 return [].concat(this.selections.items);
20116 * Returns the first selected record.
20119 getSelected : function(){
20120 return this.selections.itemAt(0);
20125 * Clears all selections.
20127 clearSelections : function(fast){
20128 if(this.locked) return;
20130 var ds = this.grid.dataSource;
20131 var s = this.selections;
20132 s.each(function(r){
20133 this.deselectRow(ds.indexOfId(r.id));
20137 this.selections.clear();
20144 * Selects all rows.
20146 selectAll : function(){
20147 if(this.locked) return;
20148 this.selections.clear();
20149 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20150 this.selectRow(i, true);
20155 * Returns True if there is a selection.
20156 * @return {Boolean}
20158 hasSelection : function(){
20159 return this.selections.length > 0;
20163 * Returns True if the specified row is selected.
20164 * @param {Number/Record} record The record or index of the record to check
20165 * @return {Boolean}
20167 isSelected : function(index){
20168 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20169 return (r && this.selections.key(r.id) ? true : false);
20173 * Returns True if the specified record id is selected.
20174 * @param {String} id The id of record to check
20175 * @return {Boolean}
20177 isIdSelected : function(id){
20178 return (this.selections.key(id) ? true : false);
20182 handleMouseDown : function(e, t){
20183 var view = this.grid.getView(), rowIndex;
20184 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20187 if(e.shiftKey && this.last !== false){
20188 var last = this.last;
20189 this.selectRange(last, rowIndex, e.ctrlKey);
20190 this.last = last; // reset the last
20191 view.focusRow(rowIndex);
20193 var isSelected = this.isSelected(rowIndex);
20194 if(e.button !== 0 && isSelected){
20195 view.focusRow(rowIndex);
20196 }else if(e.ctrlKey && isSelected){
20197 this.deselectRow(rowIndex);
20198 }else if(!isSelected){
20199 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20200 view.focusRow(rowIndex);
20203 this.fireEvent("afterselectionchange", this);
20206 handleDragableRowClick : function(grid, rowIndex, e)
20208 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20209 this.selectRow(rowIndex, false);
20210 grid.view.focusRow(rowIndex);
20211 this.fireEvent("afterselectionchange", this);
20216 * Selects multiple rows.
20217 * @param {Array} rows Array of the indexes of the row to select
20218 * @param {Boolean} keepExisting (optional) True to keep existing selections
20220 selectRows : function(rows, keepExisting){
20222 this.clearSelections();
20224 for(var i = 0, len = rows.length; i < len; i++){
20225 this.selectRow(rows[i], true);
20230 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20231 * @param {Number} startRow The index of the first row in the range
20232 * @param {Number} endRow The index of the last row in the range
20233 * @param {Boolean} keepExisting (optional) True to retain existing selections
20235 selectRange : function(startRow, endRow, keepExisting){
20236 if(this.locked) return;
20238 this.clearSelections();
20240 if(startRow <= endRow){
20241 for(var i = startRow; i <= endRow; i++){
20242 this.selectRow(i, true);
20245 for(var i = startRow; i >= endRow; i--){
20246 this.selectRow(i, true);
20252 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20253 * @param {Number} startRow The index of the first row in the range
20254 * @param {Number} endRow The index of the last row in the range
20256 deselectRange : function(startRow, endRow, preventViewNotify){
20257 if(this.locked) return;
20258 for(var i = startRow; i <= endRow; i++){
20259 this.deselectRow(i, preventViewNotify);
20265 * @param {Number} row The index of the row to select
20266 * @param {Boolean} keepExisting (optional) True to keep existing selections
20268 selectRow : function(index, keepExisting, preventViewNotify){
20269 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20270 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20271 if(!keepExisting || this.singleSelect){
20272 this.clearSelections();
20274 var r = this.grid.dataSource.getAt(index);
20275 this.selections.add(r);
20276 this.last = this.lastActive = index;
20277 if(!preventViewNotify){
20278 this.grid.getView().onRowSelect(index);
20280 this.fireEvent("rowselect", this, index, r);
20281 this.fireEvent("selectionchange", this);
20287 * @param {Number} row The index of the row to deselect
20289 deselectRow : function(index, preventViewNotify){
20290 if(this.locked) return;
20291 if(this.last == index){
20294 if(this.lastActive == index){
20295 this.lastActive = false;
20297 var r = this.grid.dataSource.getAt(index);
20298 this.selections.remove(r);
20299 if(!preventViewNotify){
20300 this.grid.getView().onRowDeselect(index);
20302 this.fireEvent("rowdeselect", this, index);
20303 this.fireEvent("selectionchange", this);
20307 restoreLast : function(){
20309 this.last = this._last;
20314 acceptsNav : function(row, col, cm){
20315 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20319 onEditorKey : function(field, e){
20320 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20325 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20327 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20329 }else if(k == e.ENTER && !e.ctrlKey){
20333 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20335 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20337 }else if(k == e.ESC){
20341 g.startEditing(newCell[0], newCell[1]);
20346 * Ext JS Library 1.1.1
20347 * Copyright(c) 2006-2007, Ext JS, LLC.
20349 * Originally Released Under LGPL - original licence link has changed is not relivant.
20352 * <script type="text/javascript">
20356 * @class Roo.bootstrap.PagingToolbar
20358 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20360 * Create a new PagingToolbar
20361 * @param {Object} config The config object
20363 Roo.bootstrap.PagingToolbar = function(config)
20365 // old args format still supported... - xtype is prefered..
20366 // created from xtype...
20367 var ds = config.dataSource;
20368 this.toolbarItems = [];
20369 if (config.items) {
20370 this.toolbarItems = config.items;
20371 // config.items = [];
20374 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20381 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20385 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20387 * @cfg {Roo.data.Store} dataSource
20388 * The underlying data store providing the paged data
20391 * @cfg {String/HTMLElement/Element} container
20392 * container The id or element that will contain the toolbar
20395 * @cfg {Boolean} displayInfo
20396 * True to display the displayMsg (defaults to false)
20399 * @cfg {Number} pageSize
20400 * The number of records to display per page (defaults to 20)
20404 * @cfg {String} displayMsg
20405 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20407 displayMsg : 'Displaying {0} - {1} of {2}',
20409 * @cfg {String} emptyMsg
20410 * The message to display when no records are found (defaults to "No data to display")
20412 emptyMsg : 'No data to display',
20414 * Customizable piece of the default paging text (defaults to "Page")
20417 beforePageText : "Page",
20419 * Customizable piece of the default paging text (defaults to "of %0")
20422 afterPageText : "of {0}",
20424 * Customizable piece of the default paging text (defaults to "First Page")
20427 firstText : "First Page",
20429 * Customizable piece of the default paging text (defaults to "Previous Page")
20432 prevText : "Previous Page",
20434 * Customizable piece of the default paging text (defaults to "Next Page")
20437 nextText : "Next Page",
20439 * Customizable piece of the default paging text (defaults to "Last Page")
20442 lastText : "Last Page",
20444 * Customizable piece of the default paging text (defaults to "Refresh")
20447 refreshText : "Refresh",
20451 onRender : function(ct, position)
20453 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20454 this.navgroup.parentId = this.id;
20455 this.navgroup.onRender(this.el, null);
20456 // add the buttons to the navgroup
20458 if(this.displayInfo){
20459 Roo.log(this.el.select('ul.navbar-nav',true).first());
20460 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20461 this.displayEl = this.el.select('.x-paging-info', true).first();
20462 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20463 // this.displayEl = navel.el.select('span',true).first();
20469 Roo.each(_this.buttons, function(e){
20470 Roo.factory(e).onRender(_this.el, null);
20474 Roo.each(_this.toolbarItems, function(e) {
20475 _this.navgroup.addItem(e);
20479 this.first = this.navgroup.addItem({
20480 tooltip: this.firstText,
20482 icon : 'fa fa-backward',
20484 preventDefault: true,
20485 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20488 this.prev = this.navgroup.addItem({
20489 tooltip: this.prevText,
20491 icon : 'fa fa-step-backward',
20493 preventDefault: true,
20494 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20496 //this.addSeparator();
20499 var field = this.navgroup.addItem( {
20501 cls : 'x-paging-position',
20503 html : this.beforePageText +
20504 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20505 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20508 this.field = field.el.select('input', true).first();
20509 this.field.on("keydown", this.onPagingKeydown, this);
20510 this.field.on("focus", function(){this.dom.select();});
20513 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20514 //this.field.setHeight(18);
20515 //this.addSeparator();
20516 this.next = this.navgroup.addItem({
20517 tooltip: this.nextText,
20519 html : ' <i class="fa fa-step-forward">',
20521 preventDefault: true,
20522 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20524 this.last = this.navgroup.addItem({
20525 tooltip: this.lastText,
20526 icon : 'fa fa-forward',
20529 preventDefault: true,
20530 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20532 //this.addSeparator();
20533 this.loading = this.navgroup.addItem({
20534 tooltip: this.refreshText,
20535 icon: 'fa fa-refresh',
20536 preventDefault: true,
20537 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20543 updateInfo : function(){
20544 if(this.displayEl){
20545 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20546 var msg = count == 0 ?
20550 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20552 this.displayEl.update(msg);
20557 onLoad : function(ds, r, o){
20558 this.cursor = o.params ? o.params.start : 0;
20559 var d = this.getPageData(),
20563 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20564 this.field.dom.value = ap;
20565 this.first.setDisabled(ap == 1);
20566 this.prev.setDisabled(ap == 1);
20567 this.next.setDisabled(ap == ps);
20568 this.last.setDisabled(ap == ps);
20569 this.loading.enable();
20574 getPageData : function(){
20575 var total = this.ds.getTotalCount();
20578 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20579 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20584 onLoadError : function(){
20585 this.loading.enable();
20589 onPagingKeydown : function(e){
20590 var k = e.getKey();
20591 var d = this.getPageData();
20593 var v = this.field.dom.value, pageNum;
20594 if(!v || isNaN(pageNum = parseInt(v, 10))){
20595 this.field.dom.value = d.activePage;
20598 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20599 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20602 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))
20604 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20605 this.field.dom.value = pageNum;
20606 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20609 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20611 var v = this.field.dom.value, pageNum;
20612 var increment = (e.shiftKey) ? 10 : 1;
20613 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20615 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20616 this.field.dom.value = d.activePage;
20619 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20621 this.field.dom.value = parseInt(v, 10) + increment;
20622 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20623 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20630 beforeLoad : function(){
20632 this.loading.disable();
20637 onClick : function(which){
20646 ds.load({params:{start: 0, limit: this.pageSize}});
20649 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20652 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20655 var total = ds.getTotalCount();
20656 var extra = total % this.pageSize;
20657 var lastStart = extra ? (total - extra) : total-this.pageSize;
20658 ds.load({params:{start: lastStart, limit: this.pageSize}});
20661 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20667 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20668 * @param {Roo.data.Store} store The data store to unbind
20670 unbind : function(ds){
20671 ds.un("beforeload", this.beforeLoad, this);
20672 ds.un("load", this.onLoad, this);
20673 ds.un("loadexception", this.onLoadError, this);
20674 ds.un("remove", this.updateInfo, this);
20675 ds.un("add", this.updateInfo, this);
20676 this.ds = undefined;
20680 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20681 * @param {Roo.data.Store} store The data store to bind
20683 bind : function(ds){
20684 ds.on("beforeload", this.beforeLoad, this);
20685 ds.on("load", this.onLoad, this);
20686 ds.on("loadexception", this.onLoadError, this);
20687 ds.on("remove", this.updateInfo, this);
20688 ds.on("add", this.updateInfo, this);
20699 * @class Roo.bootstrap.MessageBar
20700 * @extends Roo.bootstrap.Component
20701 * Bootstrap MessageBar class
20702 * @cfg {String} html contents of the MessageBar
20703 * @cfg {String} weight (info | success | warning | danger) default info
20704 * @cfg {String} beforeClass insert the bar before the given class
20705 * @cfg {Boolean} closable (true | false) default false
20706 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20709 * Create a new Element
20710 * @param {Object} config The config object
20713 Roo.bootstrap.MessageBar = function(config){
20714 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20717 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20723 beforeClass: 'bootstrap-sticky-wrap',
20725 getAutoCreate : function(){
20729 cls: 'alert alert-dismissable alert-' + this.weight,
20734 html: this.html || ''
20740 cfg.cls += ' alert-messages-fixed';
20754 onRender : function(ct, position)
20756 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20759 var cfg = Roo.apply({}, this.getAutoCreate());
20763 cfg.cls += ' ' + this.cls;
20766 cfg.style = this.style;
20768 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20770 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20773 this.el.select('>button.close').on('click', this.hide, this);
20779 if (!this.rendered) {
20785 this.fireEvent('show', this);
20791 if (!this.rendered) {
20797 this.fireEvent('hide', this);
20800 update : function()
20802 // var e = this.el.dom.firstChild;
20804 // if(this.closable){
20805 // e = e.nextSibling;
20808 // e.data = this.html || '';
20810 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20826 * @class Roo.bootstrap.Graph
20827 * @extends Roo.bootstrap.Component
20828 * Bootstrap Graph class
20832 @cfg {String} graphtype bar | vbar | pie
20833 @cfg {number} g_x coodinator | centre x (pie)
20834 @cfg {number} g_y coodinator | centre y (pie)
20835 @cfg {number} g_r radius (pie)
20836 @cfg {number} g_height height of the chart (respected by all elements in the set)
20837 @cfg {number} g_width width of the chart (respected by all elements in the set)
20838 @cfg {Object} title The title of the chart
20841 -opts (object) options for the chart
20843 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20844 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20846 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.
20847 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20849 o stretch (boolean)
20851 -opts (object) options for the pie
20854 o startAngle (number)
20855 o endAngle (number)
20859 * Create a new Input
20860 * @param {Object} config The config object
20863 Roo.bootstrap.Graph = function(config){
20864 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20870 * The img click event for the img.
20871 * @param {Roo.EventObject} e
20877 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20888 //g_colors: this.colors,
20895 getAutoCreate : function(){
20906 onRender : function(ct,position){
20907 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20908 this.raphael = Raphael(this.el.dom);
20910 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20911 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20912 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20913 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20915 r.text(160, 10, "Single Series Chart").attr(txtattr);
20916 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20917 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20918 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20920 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20921 r.barchart(330, 10, 300, 220, data1);
20922 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20923 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20926 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20927 // r.barchart(30, 30, 560, 250, xdata, {
20928 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20929 // axis : "0 0 1 1",
20930 // axisxlabels : xdata
20931 // //yvalues : cols,
20934 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20936 // this.load(null,xdata,{
20937 // axis : "0 0 1 1",
20938 // axisxlabels : xdata
20943 load : function(graphtype,xdata,opts){
20944 this.raphael.clear();
20946 graphtype = this.graphtype;
20951 var r = this.raphael,
20952 fin = function () {
20953 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20955 fout = function () {
20956 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20958 pfin = function() {
20959 this.sector.stop();
20960 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20963 this.label[0].stop();
20964 this.label[0].attr({ r: 7.5 });
20965 this.label[1].attr({ "font-weight": 800 });
20968 pfout = function() {
20969 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20972 this.label[0].animate({ r: 5 }, 500, "bounce");
20973 this.label[1].attr({ "font-weight": 400 });
20979 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20982 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20985 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20986 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20988 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20995 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21000 setTitle: function(o)
21005 initEvents: function() {
21008 this.el.on('click', this.onClick, this);
21012 onClick : function(e)
21014 Roo.log('img onclick');
21015 this.fireEvent('click', this, e);
21027 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21030 * @class Roo.bootstrap.dash.NumberBox
21031 * @extends Roo.bootstrap.Component
21032 * Bootstrap NumberBox class
21033 * @cfg {String} headline Box headline
21034 * @cfg {String} content Box content
21035 * @cfg {String} icon Box icon
21036 * @cfg {String} footer Footer text
21037 * @cfg {String} fhref Footer href
21040 * Create a new NumberBox
21041 * @param {Object} config The config object
21045 Roo.bootstrap.dash.NumberBox = function(config){
21046 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21050 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21059 getAutoCreate : function(){
21063 cls : 'small-box ',
21071 cls : 'roo-headline',
21072 html : this.headline
21076 cls : 'roo-content',
21077 html : this.content
21091 cls : 'ion ' + this.icon
21100 cls : 'small-box-footer',
21101 href : this.fhref || '#',
21105 cfg.cn.push(footer);
21112 onRender : function(ct,position){
21113 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21120 setHeadline: function (value)
21122 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21125 setFooter: function (value, href)
21127 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21130 this.el.select('a.small-box-footer',true).first().attr('href', href);
21135 setContent: function (value)
21137 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21140 initEvents: function()
21154 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21157 * @class Roo.bootstrap.dash.TabBox
21158 * @extends Roo.bootstrap.Component
21159 * Bootstrap TabBox class
21160 * @cfg {String} title Title of the TabBox
21161 * @cfg {String} icon Icon of the TabBox
21162 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21163 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21166 * Create a new TabBox
21167 * @param {Object} config The config object
21171 Roo.bootstrap.dash.TabBox = function(config){
21172 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21177 * When a pane is added
21178 * @param {Roo.bootstrap.dash.TabPane} pane
21182 * @event activatepane
21183 * When a pane is activated
21184 * @param {Roo.bootstrap.dash.TabPane} pane
21186 "activatepane" : true
21194 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21199 tabScrollable : false,
21201 getChildContainer : function()
21203 return this.el.select('.tab-content', true).first();
21206 getAutoCreate : function(){
21210 cls: 'pull-left header',
21218 cls: 'fa ' + this.icon
21224 cls: 'nav nav-tabs pull-right',
21230 if(this.tabScrollable){
21237 cls: 'nav nav-tabs pull-right',
21248 cls: 'nav-tabs-custom',
21253 cls: 'tab-content no-padding',
21261 initEvents : function()
21263 //Roo.log('add add pane handler');
21264 this.on('addpane', this.onAddPane, this);
21267 * Updates the box title
21268 * @param {String} html to set the title to.
21270 setTitle : function(value)
21272 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21274 onAddPane : function(pane)
21276 this.panes.push(pane);
21277 //Roo.log('addpane');
21279 // tabs are rendere left to right..
21280 if(!this.showtabs){
21284 var ctr = this.el.select('.nav-tabs', true).first();
21287 var existing = ctr.select('.nav-tab',true);
21288 var qty = existing.getCount();;
21291 var tab = ctr.createChild({
21293 cls : 'nav-tab' + (qty ? '' : ' active'),
21301 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21304 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21306 pane.el.addClass('active');
21311 onTabClick : function(ev,un,ob,pane)
21313 //Roo.log('tab - prev default');
21314 ev.preventDefault();
21317 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21318 pane.tab.addClass('active');
21319 //Roo.log(pane.title);
21320 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21321 // technically we should have a deactivate event.. but maybe add later.
21322 // and it should not de-activate the selected tab...
21323 this.fireEvent('activatepane', pane);
21324 pane.el.addClass('active');
21325 pane.fireEvent('activate');
21330 getActivePane : function()
21333 Roo.each(this.panes, function(p) {
21334 if(p.el.hasClass('active')){
21355 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21357 * @class Roo.bootstrap.TabPane
21358 * @extends Roo.bootstrap.Component
21359 * Bootstrap TabPane class
21360 * @cfg {Boolean} active (false | true) Default false
21361 * @cfg {String} title title of panel
21365 * Create a new TabPane
21366 * @param {Object} config The config object
21369 Roo.bootstrap.dash.TabPane = function(config){
21370 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21376 * When a pane is activated
21377 * @param {Roo.bootstrap.dash.TabPane} pane
21384 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21389 // the tabBox that this is attached to.
21392 getAutoCreate : function()
21400 cfg.cls += ' active';
21405 initEvents : function()
21407 //Roo.log('trigger add pane handler');
21408 this.parent().fireEvent('addpane', this)
21412 * Updates the tab title
21413 * @param {String} html to set the title to.
21415 setTitle: function(str)
21421 this.tab.select('a', true).first().dom.innerHTML = str;
21438 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21441 * @class Roo.bootstrap.menu.Menu
21442 * @extends Roo.bootstrap.Component
21443 * Bootstrap Menu class - container for Menu
21444 * @cfg {String} html Text of the menu
21445 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21446 * @cfg {String} icon Font awesome icon
21447 * @cfg {String} pos Menu align to (top | bottom) default bottom
21451 * Create a new Menu
21452 * @param {Object} config The config object
21456 Roo.bootstrap.menu.Menu = function(config){
21457 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21461 * @event beforeshow
21462 * Fires before this menu is displayed
21463 * @param {Roo.bootstrap.menu.Menu} this
21467 * @event beforehide
21468 * Fires before this menu is hidden
21469 * @param {Roo.bootstrap.menu.Menu} this
21474 * Fires after this menu is displayed
21475 * @param {Roo.bootstrap.menu.Menu} this
21480 * Fires after this menu is hidden
21481 * @param {Roo.bootstrap.menu.Menu} this
21486 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21487 * @param {Roo.bootstrap.menu.Menu} this
21488 * @param {Roo.EventObject} e
21495 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21499 weight : 'default',
21504 getChildContainer : function() {
21505 if(this.isSubMenu){
21509 return this.el.select('ul.dropdown-menu', true).first();
21512 getAutoCreate : function()
21517 cls : 'roo-menu-text',
21525 cls : 'fa ' + this.icon
21536 cls : 'dropdown-button btn btn-' + this.weight,
21541 cls : 'dropdown-toggle btn btn-' + this.weight,
21551 cls : 'dropdown-menu'
21557 if(this.pos == 'top'){
21558 cfg.cls += ' dropup';
21561 if(this.isSubMenu){
21564 cls : 'dropdown-menu'
21571 onRender : function(ct, position)
21573 this.isSubMenu = ct.hasClass('dropdown-submenu');
21575 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21578 initEvents : function()
21580 if(this.isSubMenu){
21584 this.hidden = true;
21586 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21587 this.triggerEl.on('click', this.onTriggerPress, this);
21589 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21590 this.buttonEl.on('click', this.onClick, this);
21596 if(this.isSubMenu){
21600 return this.el.select('ul.dropdown-menu', true).first();
21603 onClick : function(e)
21605 this.fireEvent("click", this, e);
21608 onTriggerPress : function(e)
21610 if (this.isVisible()) {
21617 isVisible : function(){
21618 return !this.hidden;
21623 this.fireEvent("beforeshow", this);
21625 this.hidden = false;
21626 this.el.addClass('open');
21628 Roo.get(document).on("mouseup", this.onMouseUp, this);
21630 this.fireEvent("show", this);
21637 this.fireEvent("beforehide", this);
21639 this.hidden = true;
21640 this.el.removeClass('open');
21642 Roo.get(document).un("mouseup", this.onMouseUp);
21644 this.fireEvent("hide", this);
21647 onMouseUp : function()
21661 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21664 * @class Roo.bootstrap.menu.Item
21665 * @extends Roo.bootstrap.Component
21666 * Bootstrap MenuItem class
21667 * @cfg {Boolean} submenu (true | false) default false
21668 * @cfg {String} html text of the item
21669 * @cfg {String} href the link
21670 * @cfg {Boolean} disable (true | false) default false
21671 * @cfg {Boolean} preventDefault (true | false) default true
21672 * @cfg {String} icon Font awesome icon
21673 * @cfg {String} pos Submenu align to (left | right) default right
21677 * Create a new Item
21678 * @param {Object} config The config object
21682 Roo.bootstrap.menu.Item = function(config){
21683 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21687 * Fires when the mouse is hovering over this menu
21688 * @param {Roo.bootstrap.menu.Item} this
21689 * @param {Roo.EventObject} e
21694 * Fires when the mouse exits this menu
21695 * @param {Roo.bootstrap.menu.Item} this
21696 * @param {Roo.EventObject} e
21702 * The raw click event for the entire grid.
21703 * @param {Roo.EventObject} e
21709 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21714 preventDefault: true,
21719 getAutoCreate : function()
21724 cls : 'roo-menu-item-text',
21732 cls : 'fa ' + this.icon
21741 href : this.href || '#',
21748 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21752 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21754 if(this.pos == 'left'){
21755 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21762 initEvents : function()
21764 this.el.on('mouseover', this.onMouseOver, this);
21765 this.el.on('mouseout', this.onMouseOut, this);
21767 this.el.select('a', true).first().on('click', this.onClick, this);
21771 onClick : function(e)
21773 if(this.preventDefault){
21774 e.preventDefault();
21777 this.fireEvent("click", this, e);
21780 onMouseOver : function(e)
21782 if(this.submenu && this.pos == 'left'){
21783 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21786 this.fireEvent("mouseover", this, e);
21789 onMouseOut : function(e)
21791 this.fireEvent("mouseout", this, e);
21803 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21806 * @class Roo.bootstrap.menu.Separator
21807 * @extends Roo.bootstrap.Component
21808 * Bootstrap Separator class
21811 * Create a new Separator
21812 * @param {Object} config The config object
21816 Roo.bootstrap.menu.Separator = function(config){
21817 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21820 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21822 getAutoCreate : function(){
21843 * @class Roo.bootstrap.Tooltip
21844 * Bootstrap Tooltip class
21845 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21846 * to determine which dom element triggers the tooltip.
21848 * It needs to add support for additional attributes like tooltip-position
21851 * Create a new Toolti
21852 * @param {Object} config The config object
21855 Roo.bootstrap.Tooltip = function(config){
21856 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21859 Roo.apply(Roo.bootstrap.Tooltip, {
21861 * @function init initialize tooltip monitoring.
21865 currentTip : false,
21866 currentRegion : false,
21872 Roo.get(document).on('mouseover', this.enter ,this);
21873 Roo.get(document).on('mouseout', this.leave, this);
21876 this.currentTip = new Roo.bootstrap.Tooltip();
21879 enter : function(ev)
21881 var dom = ev.getTarget();
21883 //Roo.log(['enter',dom]);
21884 var el = Roo.fly(dom);
21885 if (this.currentEl) {
21887 //Roo.log(this.currentEl);
21888 //Roo.log(this.currentEl.contains(dom));
21889 if (this.currentEl == el) {
21892 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21900 if (this.currentTip.el) {
21901 this.currentTip.el.hide(); // force hiding...
21906 // you can not look for children, as if el is the body.. then everythign is the child..
21907 if (!el.attr('tooltip')) { //
21908 if (!el.select("[tooltip]").elements.length) {
21911 // is the mouse over this child...?
21912 bindEl = el.select("[tooltip]").first();
21913 var xy = ev.getXY();
21914 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21915 //Roo.log("not in region.");
21918 //Roo.log("child element over..");
21921 this.currentEl = bindEl;
21922 this.currentTip.bind(bindEl);
21923 this.currentRegion = Roo.lib.Region.getRegion(dom);
21924 this.currentTip.enter();
21927 leave : function(ev)
21929 var dom = ev.getTarget();
21930 //Roo.log(['leave',dom]);
21931 if (!this.currentEl) {
21936 if (dom != this.currentEl.dom) {
21939 var xy = ev.getXY();
21940 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21943 // only activate leave if mouse cursor is outside... bounding box..
21948 if (this.currentTip) {
21949 this.currentTip.leave();
21951 //Roo.log('clear currentEl');
21952 this.currentEl = false;
21957 'left' : ['r-l', [-2,0], 'right'],
21958 'right' : ['l-r', [2,0], 'left'],
21959 'bottom' : ['t-b', [0,2], 'top'],
21960 'top' : [ 'b-t', [0,-2], 'bottom']
21966 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21971 delay : null, // can be { show : 300 , hide: 500}
21975 hoverState : null, //???
21977 placement : 'bottom',
21979 getAutoCreate : function(){
21986 cls : 'tooltip-arrow'
21989 cls : 'tooltip-inner'
21996 bind : function(el)
22002 enter : function () {
22004 if (this.timeout != null) {
22005 clearTimeout(this.timeout);
22008 this.hoverState = 'in';
22009 //Roo.log("enter - show");
22010 if (!this.delay || !this.delay.show) {
22015 this.timeout = setTimeout(function () {
22016 if (_t.hoverState == 'in') {
22019 }, this.delay.show);
22023 clearTimeout(this.timeout);
22025 this.hoverState = 'out';
22026 if (!this.delay || !this.delay.hide) {
22032 this.timeout = setTimeout(function () {
22033 //Roo.log("leave - timeout");
22035 if (_t.hoverState == 'out') {
22037 Roo.bootstrap.Tooltip.currentEl = false;
22045 this.render(document.body);
22048 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22050 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22052 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22054 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22056 var placement = typeof this.placement == 'function' ?
22057 this.placement.call(this, this.el, on_el) :
22060 var autoToken = /\s?auto?\s?/i;
22061 var autoPlace = autoToken.test(placement);
22063 placement = placement.replace(autoToken, '') || 'top';
22067 //this.el.setXY([0,0]);
22069 //this.el.dom.style.display='block';
22070 this.el.addClass(placement);
22072 //this.el.appendTo(on_el);
22074 var p = this.getPosition();
22075 var box = this.el.getBox();
22080 var align = Roo.bootstrap.Tooltip.alignment[placement];
22081 this.el.alignTo(this.bindEl, align[0],align[1]);
22082 //var arrow = this.el.select('.arrow',true).first();
22083 //arrow.set(align[2],
22085 this.el.addClass('in fade');
22086 this.hoverState = null;
22088 if (this.el.hasClass('fade')) {
22099 //this.el.setXY([0,0]);
22100 this.el.removeClass('in');
22116 * @class Roo.bootstrap.LocationPicker
22117 * @extends Roo.bootstrap.Component
22118 * Bootstrap LocationPicker class
22119 * @cfg {Number} latitude Position when init default 0
22120 * @cfg {Number} longitude Position when init default 0
22121 * @cfg {Number} zoom default 15
22122 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22123 * @cfg {Boolean} mapTypeControl default false
22124 * @cfg {Boolean} disableDoubleClickZoom default false
22125 * @cfg {Boolean} scrollwheel default true
22126 * @cfg {Boolean} streetViewControl default false
22127 * @cfg {Number} radius default 0
22128 * @cfg {String} locationName
22129 * @cfg {Boolean} draggable default true
22130 * @cfg {Boolean} enableAutocomplete default false
22131 * @cfg {Boolean} enableReverseGeocode default true
22132 * @cfg {String} markerTitle
22135 * Create a new LocationPicker
22136 * @param {Object} config The config object
22140 Roo.bootstrap.LocationPicker = function(config){
22142 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22147 * Fires when the picker initialized.
22148 * @param {Roo.bootstrap.LocationPicker} this
22149 * @param {Google Location} location
22153 * @event positionchanged
22154 * Fires when the picker position changed.
22155 * @param {Roo.bootstrap.LocationPicker} this
22156 * @param {Google Location} location
22158 positionchanged : true,
22161 * Fires when the map resize.
22162 * @param {Roo.bootstrap.LocationPicker} this
22167 * Fires when the map show.
22168 * @param {Roo.bootstrap.LocationPicker} this
22173 * Fires when the map hide.
22174 * @param {Roo.bootstrap.LocationPicker} this
22179 * Fires when click the map.
22180 * @param {Roo.bootstrap.LocationPicker} this
22181 * @param {Map event} e
22185 * @event mapRightClick
22186 * Fires when right click the map.
22187 * @param {Roo.bootstrap.LocationPicker} this
22188 * @param {Map event} e
22190 mapRightClick : true,
22192 * @event markerClick
22193 * Fires when click the marker.
22194 * @param {Roo.bootstrap.LocationPicker} this
22195 * @param {Map event} e
22197 markerClick : true,
22199 * @event markerRightClick
22200 * Fires when right click the marker.
22201 * @param {Roo.bootstrap.LocationPicker} this
22202 * @param {Map event} e
22204 markerRightClick : true,
22206 * @event OverlayViewDraw
22207 * Fires when OverlayView Draw
22208 * @param {Roo.bootstrap.LocationPicker} this
22210 OverlayViewDraw : true,
22212 * @event OverlayViewOnAdd
22213 * Fires when OverlayView Draw
22214 * @param {Roo.bootstrap.LocationPicker} this
22216 OverlayViewOnAdd : true,
22218 * @event OverlayViewOnRemove
22219 * Fires when OverlayView Draw
22220 * @param {Roo.bootstrap.LocationPicker} this
22222 OverlayViewOnRemove : true,
22224 * @event OverlayViewShow
22225 * Fires when OverlayView Draw
22226 * @param {Roo.bootstrap.LocationPicker} this
22227 * @param {Pixel} cpx
22229 OverlayViewShow : true,
22231 * @event OverlayViewHide
22232 * Fires when OverlayView Draw
22233 * @param {Roo.bootstrap.LocationPicker} this
22235 OverlayViewHide : true
22240 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22242 gMapContext: false,
22248 mapTypeControl: false,
22249 disableDoubleClickZoom: false,
22251 streetViewControl: false,
22255 enableAutocomplete: false,
22256 enableReverseGeocode: true,
22259 getAutoCreate: function()
22264 cls: 'roo-location-picker'
22270 initEvents: function(ct, position)
22272 if(!this.el.getWidth() || this.isApplied()){
22276 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22281 initial: function()
22283 if(!this.mapTypeId){
22284 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22287 this.gMapContext = this.GMapContext();
22289 this.initOverlayView();
22291 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22295 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22296 _this.setPosition(_this.gMapContext.marker.position);
22299 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22300 _this.fireEvent('mapClick', this, event);
22304 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22305 _this.fireEvent('mapRightClick', this, event);
22309 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22310 _this.fireEvent('markerClick', this, event);
22314 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22315 _this.fireEvent('markerRightClick', this, event);
22319 this.setPosition(this.gMapContext.location);
22321 this.fireEvent('initial', this, this.gMapContext.location);
22324 initOverlayView: function()
22328 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22332 _this.fireEvent('OverlayViewDraw', _this);
22337 _this.fireEvent('OverlayViewOnAdd', _this);
22340 onRemove: function()
22342 _this.fireEvent('OverlayViewOnRemove', _this);
22345 show: function(cpx)
22347 _this.fireEvent('OverlayViewShow', _this, cpx);
22352 _this.fireEvent('OverlayViewHide', _this);
22358 fromLatLngToContainerPixel: function(event)
22360 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22363 isApplied: function()
22365 return this.getGmapContext() == false ? false : true;
22368 getGmapContext: function()
22370 return this.gMapContext
22373 GMapContext: function()
22375 var position = new google.maps.LatLng(this.latitude, this.longitude);
22377 var _map = new google.maps.Map(this.el.dom, {
22380 mapTypeId: this.mapTypeId,
22381 mapTypeControl: this.mapTypeControl,
22382 disableDoubleClickZoom: this.disableDoubleClickZoom,
22383 scrollwheel: this.scrollwheel,
22384 streetViewControl: this.streetViewControl,
22385 locationName: this.locationName,
22386 draggable: this.draggable,
22387 enableAutocomplete: this.enableAutocomplete,
22388 enableReverseGeocode: this.enableReverseGeocode
22391 var _marker = new google.maps.Marker({
22392 position: position,
22394 title: this.markerTitle,
22395 draggable: this.draggable
22402 location: position,
22403 radius: this.radius,
22404 locationName: this.locationName,
22405 addressComponents: {
22406 formatted_address: null,
22407 addressLine1: null,
22408 addressLine2: null,
22410 streetNumber: null,
22414 stateOrProvince: null
22417 domContainer: this.el.dom,
22418 geodecoder: new google.maps.Geocoder()
22422 drawCircle: function(center, radius, options)
22424 if (this.gMapContext.circle != null) {
22425 this.gMapContext.circle.setMap(null);
22429 options = Roo.apply({}, options, {
22430 strokeColor: "#0000FF",
22431 strokeOpacity: .35,
22433 fillColor: "#0000FF",
22437 options.map = this.gMapContext.map;
22438 options.radius = radius;
22439 options.center = center;
22440 this.gMapContext.circle = new google.maps.Circle(options);
22441 return this.gMapContext.circle;
22447 setPosition: function(location)
22449 this.gMapContext.location = location;
22450 this.gMapContext.marker.setPosition(location);
22451 this.gMapContext.map.panTo(location);
22452 this.drawCircle(location, this.gMapContext.radius, {});
22456 if (this.gMapContext.settings.enableReverseGeocode) {
22457 this.gMapContext.geodecoder.geocode({
22458 latLng: this.gMapContext.location
22459 }, function(results, status) {
22461 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22462 _this.gMapContext.locationName = results[0].formatted_address;
22463 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22465 _this.fireEvent('positionchanged', this, location);
22472 this.fireEvent('positionchanged', this, location);
22477 google.maps.event.trigger(this.gMapContext.map, "resize");
22479 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22481 this.fireEvent('resize', this);
22484 setPositionByLatLng: function(latitude, longitude)
22486 this.setPosition(new google.maps.LatLng(latitude, longitude));
22489 getCurrentPosition: function()
22492 latitude: this.gMapContext.location.lat(),
22493 longitude: this.gMapContext.location.lng()
22497 getAddressName: function()
22499 return this.gMapContext.locationName;
22502 getAddressComponents: function()
22504 return this.gMapContext.addressComponents;
22507 address_component_from_google_geocode: function(address_components)
22511 for (var i = 0; i < address_components.length; i++) {
22512 var component = address_components[i];
22513 if (component.types.indexOf("postal_code") >= 0) {
22514 result.postalCode = component.short_name;
22515 } else if (component.types.indexOf("street_number") >= 0) {
22516 result.streetNumber = component.short_name;
22517 } else if (component.types.indexOf("route") >= 0) {
22518 result.streetName = component.short_name;
22519 } else if (component.types.indexOf("neighborhood") >= 0) {
22520 result.city = component.short_name;
22521 } else if (component.types.indexOf("locality") >= 0) {
22522 result.city = component.short_name;
22523 } else if (component.types.indexOf("sublocality") >= 0) {
22524 result.district = component.short_name;
22525 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22526 result.stateOrProvince = component.short_name;
22527 } else if (component.types.indexOf("country") >= 0) {
22528 result.country = component.short_name;
22532 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22533 result.addressLine2 = "";
22537 setZoomLevel: function(zoom)
22539 this.gMapContext.map.setZoom(zoom);
22552 this.fireEvent('show', this);
22563 this.fireEvent('hide', this);
22568 Roo.apply(Roo.bootstrap.LocationPicker, {
22570 OverlayView : function(map, options)
22572 options = options || {};
22586 * @class Roo.bootstrap.Alert
22587 * @extends Roo.bootstrap.Component
22588 * Bootstrap Alert class
22589 * @cfg {String} title The title of alert
22590 * @cfg {String} html The content of alert
22591 * @cfg {String} weight ( success | info | warning | danger )
22592 * @cfg {String} faicon font-awesomeicon
22595 * Create a new alert
22596 * @param {Object} config The config object
22600 Roo.bootstrap.Alert = function(config){
22601 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22605 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22612 getAutoCreate : function()
22621 cls : 'roo-alert-icon'
22626 cls : 'roo-alert-title',
22631 cls : 'roo-alert-text',
22638 cfg.cn[0].cls += ' fa ' + this.faicon;
22642 cfg.cls += ' alert-' + this.weight;
22648 initEvents: function()
22650 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22653 setTitle : function(str)
22655 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22658 setText : function(str)
22660 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22663 setWeight : function(weight)
22666 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22669 this.weight = weight;
22671 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22674 setIcon : function(icon)
22677 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22682 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);