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..
11786 if(!this.multiple){
11791 this.setValue(this.originalValue);
11792 this.clearInvalid();
11793 this.lastData = false;
11795 this.view.clearSelections();
11799 findRecord : function(prop, value){
11801 if(this.store.getCount() > 0){
11802 this.store.each(function(r){
11803 if(r.data[prop] == value){
11813 getName: function()
11815 // returns hidden if it's set..
11816 if (!this.rendered) {return ''};
11817 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11821 onViewMove : function(e, t){
11822 this.inKeyMode = false;
11826 onViewOver : function(e, t){
11827 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11830 var item = this.view.findItemFromChild(t);
11833 var index = this.view.indexOf(item);
11834 this.select(index, false);
11839 onViewClick : function(view, doFocus, el, e)
11841 var index = this.view.getSelectedIndexes()[0];
11843 var r = this.store.getAt(index);
11847 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11854 Roo.each(this.tickItems, function(v,k){
11856 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11857 _this.tickItems.splice(k, 1);
11859 if(typeof(e) == 'undefined' && view == false){
11860 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11872 this.tickItems.push(r.data);
11874 if(typeof(e) == 'undefined' && view == false){
11875 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11882 this.onSelect(r, index);
11884 if(doFocus !== false && !this.blockFocus){
11885 this.inputEl().focus();
11890 restrictHeight : function(){
11891 //this.innerList.dom.style.height = '';
11892 //var inner = this.innerList.dom;
11893 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11894 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11895 //this.list.beginUpdate();
11896 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11897 this.list.alignTo(this.inputEl(), this.listAlign);
11898 this.list.alignTo(this.inputEl(), this.listAlign);
11899 //this.list.endUpdate();
11903 onEmptyResults : function(){
11905 if(this.tickable && this.editable){
11906 this.restrictHeight();
11914 * Returns true if the dropdown list is expanded, else false.
11916 isExpanded : function(){
11917 return this.list.isVisible();
11921 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11922 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11923 * @param {String} value The data value of the item to select
11924 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11925 * selected item if it is not currently in view (defaults to true)
11926 * @return {Boolean} True if the value matched an item in the list, else false
11928 selectByValue : function(v, scrollIntoView){
11929 if(v !== undefined && v !== null){
11930 var r = this.findRecord(this.valueField || this.displayField, v);
11932 this.select(this.store.indexOf(r), scrollIntoView);
11940 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11941 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11942 * @param {Number} index The zero-based index of the list item to select
11943 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11944 * selected item if it is not currently in view (defaults to true)
11946 select : function(index, scrollIntoView){
11947 this.selectedIndex = index;
11948 this.view.select(index);
11949 if(scrollIntoView !== false){
11950 var el = this.view.getNode(index);
11952 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11955 this.list.scrollChildIntoView(el, false);
11961 selectNext : function(){
11962 var ct = this.store.getCount();
11964 if(this.selectedIndex == -1){
11966 }else if(this.selectedIndex < ct-1){
11967 this.select(this.selectedIndex+1);
11973 selectPrev : function(){
11974 var ct = this.store.getCount();
11976 if(this.selectedIndex == -1){
11978 }else if(this.selectedIndex != 0){
11979 this.select(this.selectedIndex-1);
11985 onKeyUp : function(e){
11986 if(this.editable !== false && !e.isSpecialKey()){
11987 this.lastKey = e.getKey();
11988 this.dqTask.delay(this.queryDelay);
11993 validateBlur : function(){
11994 return !this.list || !this.list.isVisible();
11998 initQuery : function(){
12000 var v = this.getRawValue();
12002 if(this.tickable && this.editable){
12003 v = this.tickableInputEl().getValue();
12010 doForce : function(){
12011 if(this.inputEl().dom.value.length > 0){
12012 this.inputEl().dom.value =
12013 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12019 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12020 * query allowing the query action to be canceled if needed.
12021 * @param {String} query The SQL query to execute
12022 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12023 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12024 * saved in the current store (defaults to false)
12026 doQuery : function(q, forceAll){
12028 if(q === undefined || q === null){
12033 forceAll: forceAll,
12037 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12042 forceAll = qe.forceAll;
12043 if(forceAll === true || (q.length >= this.minChars)){
12045 this.hasQuery = true;
12047 if(this.lastQuery != q || this.alwaysQuery){
12048 this.lastQuery = q;
12049 if(this.mode == 'local'){
12050 this.selectedIndex = -1;
12052 this.store.clearFilter();
12054 this.store.filter(this.displayField, q);
12059 this.store.baseParams[this.queryParam] = q;
12061 var options = {params : this.getParams(q)};
12064 options.add = true;
12065 options.params.start = this.page * this.pageSize;
12068 this.store.load(options);
12071 * this code will make the page width larger, at the beginning, the list not align correctly,
12072 * we should expand the list on onLoad
12073 * so command out it
12078 this.selectedIndex = -1;
12083 this.loadNext = false;
12087 getParams : function(q){
12089 //p[this.queryParam] = q;
12093 p.limit = this.pageSize;
12099 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12101 collapse : function(){
12102 if(!this.isExpanded()){
12109 this.hasFocus = false;
12111 this.cancelBtn.hide();
12112 this.trigger.show();
12115 this.tickableInputEl().dom.value = '';
12116 this.tickableInputEl().blur();
12121 Roo.get(document).un('mousedown', this.collapseIf, this);
12122 Roo.get(document).un('mousewheel', this.collapseIf, this);
12123 if (!this.editable) {
12124 Roo.get(document).un('keydown', this.listKeyPress, this);
12126 this.fireEvent('collapse', this);
12130 collapseIf : function(e){
12131 var in_combo = e.within(this.el);
12132 var in_list = e.within(this.list);
12133 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12135 if (in_combo || in_list || is_list) {
12136 //e.stopPropagation();
12141 this.onTickableFooterButtonClick(e, false, false);
12149 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12151 expand : function(){
12153 if(this.isExpanded() || !this.hasFocus){
12157 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12158 this.list.setWidth(lw);
12165 this.restrictHeight();
12169 this.tickItems = Roo.apply([], this.item);
12172 this.cancelBtn.show();
12173 this.trigger.hide();
12176 this.tickableInputEl().focus();
12181 Roo.get(document).on('mousedown', this.collapseIf, this);
12182 Roo.get(document).on('mousewheel', this.collapseIf, this);
12183 if (!this.editable) {
12184 Roo.get(document).on('keydown', this.listKeyPress, this);
12187 this.fireEvent('expand', this);
12191 // Implements the default empty TriggerField.onTriggerClick function
12192 onTriggerClick : function(e)
12194 Roo.log('trigger click');
12196 if(this.disabled || !this.triggerList){
12201 this.loadNext = false;
12203 if(this.isExpanded()){
12205 if (!this.blockFocus) {
12206 this.inputEl().focus();
12210 this.hasFocus = true;
12211 if(this.triggerAction == 'all') {
12212 this.doQuery(this.allQuery, true);
12214 this.doQuery(this.getRawValue());
12216 if (!this.blockFocus) {
12217 this.inputEl().focus();
12222 onTickableTriggerClick : function(e)
12229 this.loadNext = false;
12230 this.hasFocus = true;
12232 if(this.triggerAction == 'all') {
12233 this.doQuery(this.allQuery, true);
12235 this.doQuery(this.getRawValue());
12239 onSearchFieldClick : function(e)
12241 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12242 this.onTickableFooterButtonClick(e, false, false);
12246 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12251 this.loadNext = false;
12252 this.hasFocus = true;
12254 if(this.triggerAction == 'all') {
12255 this.doQuery(this.allQuery, true);
12257 this.doQuery(this.getRawValue());
12261 listKeyPress : function(e)
12263 //Roo.log('listkeypress');
12264 // scroll to first matching element based on key pres..
12265 if (e.isSpecialKey()) {
12268 var k = String.fromCharCode(e.getKey()).toUpperCase();
12271 var csel = this.view.getSelectedNodes();
12272 var cselitem = false;
12274 var ix = this.view.indexOf(csel[0]);
12275 cselitem = this.store.getAt(ix);
12276 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12282 this.store.each(function(v) {
12284 // start at existing selection.
12285 if (cselitem.id == v.id) {
12291 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12292 match = this.store.indexOf(v);
12298 if (match === false) {
12299 return true; // no more action?
12302 this.view.select(match);
12303 var sn = Roo.get(this.view.getSelectedNodes()[0])
12304 sn.scrollIntoView(sn.dom.parentNode, false);
12307 onViewScroll : function(e, t){
12309 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){
12313 this.hasQuery = true;
12315 this.loading = this.list.select('.loading', true).first();
12317 if(this.loading === null){
12318 this.list.createChild({
12320 cls: 'loading select2-more-results select2-active',
12321 html: 'Loading more results...'
12324 this.loading = this.list.select('.loading', true).first();
12326 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12328 this.loading.hide();
12331 this.loading.show();
12336 this.loadNext = true;
12338 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12343 addItem : function(o)
12345 var dv = ''; // display value
12347 if (this.displayField) {
12348 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12350 // this is an error condition!!!
12351 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12358 var choice = this.choices.createChild({
12360 cls: 'select2-search-choice',
12369 cls: 'select2-search-choice-close',
12374 }, this.searchField);
12376 var close = choice.select('a.select2-search-choice-close', true).first()
12378 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12386 this.inputEl().dom.value = '';
12391 onRemoveItem : function(e, _self, o)
12393 e.preventDefault();
12395 this.lastItem = Roo.apply([], this.item);
12397 var index = this.item.indexOf(o.data) * 1;
12400 Roo.log('not this item?!');
12404 this.item.splice(index, 1);
12409 this.fireEvent('remove', this, e);
12415 syncValue : function()
12417 if(!this.item.length){
12424 Roo.each(this.item, function(i){
12425 if(_this.valueField){
12426 value.push(i[_this.valueField]);
12433 this.value = value.join(',');
12435 if(this.hiddenField){
12436 this.hiddenField.dom.value = this.value;
12440 clearItem : function()
12442 if(!this.multiple){
12448 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12457 inputEl: function ()
12460 return this.searchField;
12462 return this.el.select('input.form-control',true).first();
12466 onTickableFooterButtonClick : function(e, btn, el)
12468 e.preventDefault();
12470 this.lastItem = Roo.apply([], this.item);
12472 if(btn && btn.name == 'cancel'){
12473 this.tickItems = Roo.apply([], this.item);
12482 Roo.each(this.tickItems, function(o){
12490 validate : function()
12492 var v = this.getRawValue();
12495 v = this.getValue();
12498 if(this.disabled || this.allowBlank || v.length){
12503 this.markInvalid();
12507 tickableInputEl : function()
12509 if(!this.tickable || !this.editable){
12510 return this.inputEl();
12513 return this.inputEl().select('.select2-search-field-input', true).first();
12519 * @cfg {Boolean} grow
12523 * @cfg {Number} growMin
12527 * @cfg {Number} growMax
12537 * Ext JS Library 1.1.1
12538 * Copyright(c) 2006-2007, Ext JS, LLC.
12540 * Originally Released Under LGPL - original licence link has changed is not relivant.
12543 * <script type="text/javascript">
12548 * @extends Roo.util.Observable
12549 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12550 * This class also supports single and multi selection modes. <br>
12551 * Create a data model bound view:
12553 var store = new Roo.data.Store(...);
12555 var view = new Roo.View({
12557 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12559 singleSelect: true,
12560 selectedClass: "ydataview-selected",
12564 // listen for node click?
12565 view.on("click", function(vw, index, node, e){
12566 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12570 dataModel.load("foobar.xml");
12572 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12574 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12575 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12577 * Note: old style constructor is still suported (container, template, config)
12580 * Create a new View
12581 * @param {Object} config The config object
12584 Roo.View = function(config, depreciated_tpl, depreciated_config){
12586 this.parent = false;
12588 if (typeof(depreciated_tpl) == 'undefined') {
12589 // new way.. - universal constructor.
12590 Roo.apply(this, config);
12591 this.el = Roo.get(this.el);
12594 this.el = Roo.get(config);
12595 this.tpl = depreciated_tpl;
12596 Roo.apply(this, depreciated_config);
12598 this.wrapEl = this.el.wrap().wrap();
12599 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12602 if(typeof(this.tpl) == "string"){
12603 this.tpl = new Roo.Template(this.tpl);
12605 // support xtype ctors..
12606 this.tpl = new Roo.factory(this.tpl, Roo);
12610 this.tpl.compile();
12615 * @event beforeclick
12616 * Fires before a click is processed. Returns false to cancel the default action.
12617 * @param {Roo.View} this
12618 * @param {Number} index The index of the target node
12619 * @param {HTMLElement} node The target node
12620 * @param {Roo.EventObject} e The raw event object
12622 "beforeclick" : true,
12625 * Fires when a template node is clicked.
12626 * @param {Roo.View} this
12627 * @param {Number} index The index of the target node
12628 * @param {HTMLElement} node The target node
12629 * @param {Roo.EventObject} e The raw event object
12634 * Fires when a template node is double clicked.
12635 * @param {Roo.View} this
12636 * @param {Number} index The index of the target node
12637 * @param {HTMLElement} node The target node
12638 * @param {Roo.EventObject} e The raw event object
12642 * @event contextmenu
12643 * Fires when a template node is right clicked.
12644 * @param {Roo.View} this
12645 * @param {Number} index The index of the target node
12646 * @param {HTMLElement} node The target node
12647 * @param {Roo.EventObject} e The raw event object
12649 "contextmenu" : true,
12651 * @event selectionchange
12652 * Fires when the selected nodes change.
12653 * @param {Roo.View} this
12654 * @param {Array} selections Array of the selected nodes
12656 "selectionchange" : true,
12659 * @event beforeselect
12660 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12661 * @param {Roo.View} this
12662 * @param {HTMLElement} node The node to be selected
12663 * @param {Array} selections Array of currently selected nodes
12665 "beforeselect" : true,
12667 * @event preparedata
12668 * Fires on every row to render, to allow you to change the data.
12669 * @param {Roo.View} this
12670 * @param {Object} data to be rendered (change this)
12672 "preparedata" : true
12680 "click": this.onClick,
12681 "dblclick": this.onDblClick,
12682 "contextmenu": this.onContextMenu,
12686 this.selections = [];
12688 this.cmp = new Roo.CompositeElementLite([]);
12690 this.store = Roo.factory(this.store, Roo.data);
12691 this.setStore(this.store, true);
12694 if ( this.footer && this.footer.xtype) {
12696 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12698 this.footer.dataSource = this.store
12699 this.footer.container = fctr;
12700 this.footer = Roo.factory(this.footer, Roo);
12701 fctr.insertFirst(this.el);
12703 // this is a bit insane - as the paging toolbar seems to detach the el..
12704 // dom.parentNode.parentNode.parentNode
12705 // they get detached?
12709 Roo.View.superclass.constructor.call(this);
12714 Roo.extend(Roo.View, Roo.util.Observable, {
12717 * @cfg {Roo.data.Store} store Data store to load data from.
12722 * @cfg {String|Roo.Element} el The container element.
12727 * @cfg {String|Roo.Template} tpl The template used by this View
12731 * @cfg {String} dataName the named area of the template to use as the data area
12732 * Works with domtemplates roo-name="name"
12736 * @cfg {String} selectedClass The css class to add to selected nodes
12738 selectedClass : "x-view-selected",
12740 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12745 * @cfg {String} text to display on mask (default Loading)
12749 * @cfg {Boolean} multiSelect Allow multiple selection
12751 multiSelect : false,
12753 * @cfg {Boolean} singleSelect Allow single selection
12755 singleSelect: false,
12758 * @cfg {Boolean} toggleSelect - selecting
12760 toggleSelect : false,
12763 * @cfg {Boolean} tickable - selecting
12768 * Returns the element this view is bound to.
12769 * @return {Roo.Element}
12771 getEl : function(){
12772 return this.wrapEl;
12778 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12780 refresh : function(){
12781 //Roo.log('refresh');
12784 // if we are using something like 'domtemplate', then
12785 // the what gets used is:
12786 // t.applySubtemplate(NAME, data, wrapping data..)
12787 // the outer template then get' applied with
12788 // the store 'extra data'
12789 // and the body get's added to the
12790 // roo-name="data" node?
12791 // <span class='roo-tpl-{name}'></span> ?????
12795 this.clearSelections();
12796 this.el.update("");
12798 var records = this.store.getRange();
12799 if(records.length < 1) {
12801 // is this valid?? = should it render a template??
12803 this.el.update(this.emptyText);
12807 if (this.dataName) {
12808 this.el.update(t.apply(this.store.meta)); //????
12809 el = this.el.child('.roo-tpl-' + this.dataName);
12812 for(var i = 0, len = records.length; i < len; i++){
12813 var data = this.prepareData(records[i].data, i, records[i]);
12814 this.fireEvent("preparedata", this, data, i, records[i]);
12816 var d = Roo.apply({}, data);
12819 Roo.apply(d, {'roo-id' : Roo.id()});
12823 Roo.each(this.parent.item, function(item){
12824 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12827 Roo.apply(d, {'roo-data-checked' : 'checked'});
12831 html[html.length] = Roo.util.Format.trim(
12833 t.applySubtemplate(this.dataName, d, this.store.meta) :
12840 el.update(html.join(""));
12841 this.nodes = el.dom.childNodes;
12842 this.updateIndexes(0);
12847 * Function to override to reformat the data that is sent to
12848 * the template for each node.
12849 * DEPRICATED - use the preparedata event handler.
12850 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12851 * a JSON object for an UpdateManager bound view).
12853 prepareData : function(data, index, record)
12855 this.fireEvent("preparedata", this, data, index, record);
12859 onUpdate : function(ds, record){
12860 // Roo.log('on update');
12861 this.clearSelections();
12862 var index = this.store.indexOf(record);
12863 var n = this.nodes[index];
12864 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12865 n.parentNode.removeChild(n);
12866 this.updateIndexes(index, index);
12872 onAdd : function(ds, records, index)
12874 //Roo.log(['on Add', ds, records, index] );
12875 this.clearSelections();
12876 if(this.nodes.length == 0){
12880 var n = this.nodes[index];
12881 for(var i = 0, len = records.length; i < len; i++){
12882 var d = this.prepareData(records[i].data, i, records[i]);
12884 this.tpl.insertBefore(n, d);
12887 this.tpl.append(this.el, d);
12890 this.updateIndexes(index);
12893 onRemove : function(ds, record, index){
12894 // Roo.log('onRemove');
12895 this.clearSelections();
12896 var el = this.dataName ?
12897 this.el.child('.roo-tpl-' + this.dataName) :
12900 el.dom.removeChild(this.nodes[index]);
12901 this.updateIndexes(index);
12905 * Refresh an individual node.
12906 * @param {Number} index
12908 refreshNode : function(index){
12909 this.onUpdate(this.store, this.store.getAt(index));
12912 updateIndexes : function(startIndex, endIndex){
12913 var ns = this.nodes;
12914 startIndex = startIndex || 0;
12915 endIndex = endIndex || ns.length - 1;
12916 for(var i = startIndex; i <= endIndex; i++){
12917 ns[i].nodeIndex = i;
12922 * Changes the data store this view uses and refresh the view.
12923 * @param {Store} store
12925 setStore : function(store, initial){
12926 if(!initial && this.store){
12927 this.store.un("datachanged", this.refresh);
12928 this.store.un("add", this.onAdd);
12929 this.store.un("remove", this.onRemove);
12930 this.store.un("update", this.onUpdate);
12931 this.store.un("clear", this.refresh);
12932 this.store.un("beforeload", this.onBeforeLoad);
12933 this.store.un("load", this.onLoad);
12934 this.store.un("loadexception", this.onLoad);
12938 store.on("datachanged", this.refresh, this);
12939 store.on("add", this.onAdd, this);
12940 store.on("remove", this.onRemove, this);
12941 store.on("update", this.onUpdate, this);
12942 store.on("clear", this.refresh, this);
12943 store.on("beforeload", this.onBeforeLoad, this);
12944 store.on("load", this.onLoad, this);
12945 store.on("loadexception", this.onLoad, this);
12953 * onbeforeLoad - masks the loading area.
12956 onBeforeLoad : function(store,opts)
12958 //Roo.log('onBeforeLoad');
12960 this.el.update("");
12962 this.el.mask(this.mask ? this.mask : "Loading" );
12964 onLoad : function ()
12971 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12972 * @param {HTMLElement} node
12973 * @return {HTMLElement} The template node
12975 findItemFromChild : function(node){
12976 var el = this.dataName ?
12977 this.el.child('.roo-tpl-' + this.dataName,true) :
12980 if(!node || node.parentNode == el){
12983 var p = node.parentNode;
12984 while(p && p != el){
12985 if(p.parentNode == el){
12994 onClick : function(e){
12995 var item = this.findItemFromChild(e.getTarget());
12997 var index = this.indexOf(item);
12998 if(this.onItemClick(item, index, e) !== false){
12999 this.fireEvent("click", this, index, item, e);
13002 this.clearSelections();
13007 onContextMenu : function(e){
13008 var item = this.findItemFromChild(e.getTarget());
13010 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13015 onDblClick : function(e){
13016 var item = this.findItemFromChild(e.getTarget());
13018 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13022 onItemClick : function(item, index, e)
13024 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13027 if (this.toggleSelect) {
13028 var m = this.isSelected(item) ? 'unselect' : 'select';
13031 _t[m](item, true, false);
13034 if(this.multiSelect || this.singleSelect){
13035 if(this.multiSelect && e.shiftKey && this.lastSelection){
13036 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13038 this.select(item, this.multiSelect && e.ctrlKey);
13039 this.lastSelection = item;
13042 if(!this.tickable){
13043 e.preventDefault();
13051 * Get the number of selected nodes.
13054 getSelectionCount : function(){
13055 return this.selections.length;
13059 * Get the currently selected nodes.
13060 * @return {Array} An array of HTMLElements
13062 getSelectedNodes : function(){
13063 return this.selections;
13067 * Get the indexes of the selected nodes.
13070 getSelectedIndexes : function(){
13071 var indexes = [], s = this.selections;
13072 for(var i = 0, len = s.length; i < len; i++){
13073 indexes.push(s[i].nodeIndex);
13079 * Clear all selections
13080 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13082 clearSelections : function(suppressEvent){
13083 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13084 this.cmp.elements = this.selections;
13085 this.cmp.removeClass(this.selectedClass);
13086 this.selections = [];
13087 if(!suppressEvent){
13088 this.fireEvent("selectionchange", this, this.selections);
13094 * Returns true if the passed node is selected
13095 * @param {HTMLElement/Number} node The node or node index
13096 * @return {Boolean}
13098 isSelected : function(node){
13099 var s = this.selections;
13103 node = this.getNode(node);
13104 return s.indexOf(node) !== -1;
13109 * @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
13110 * @param {Boolean} keepExisting (optional) true to keep existing selections
13111 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13113 select : function(nodeInfo, keepExisting, suppressEvent){
13114 if(nodeInfo instanceof Array){
13116 this.clearSelections(true);
13118 for(var i = 0, len = nodeInfo.length; i < len; i++){
13119 this.select(nodeInfo[i], true, true);
13123 var node = this.getNode(nodeInfo);
13124 if(!node || this.isSelected(node)){
13125 return; // already selected.
13128 this.clearSelections(true);
13131 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13132 Roo.fly(node).addClass(this.selectedClass);
13133 this.selections.push(node);
13134 if(!suppressEvent){
13135 this.fireEvent("selectionchange", this, this.selections);
13143 * @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
13144 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13145 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13147 unselect : function(nodeInfo, keepExisting, suppressEvent)
13149 if(nodeInfo instanceof Array){
13150 Roo.each(this.selections, function(s) {
13151 this.unselect(s, nodeInfo);
13155 var node = this.getNode(nodeInfo);
13156 if(!node || !this.isSelected(node)){
13157 //Roo.log("not selected");
13158 return; // not selected.
13162 Roo.each(this.selections, function(s) {
13164 Roo.fly(node).removeClass(this.selectedClass);
13171 this.selections= ns;
13172 this.fireEvent("selectionchange", this, this.selections);
13176 * Gets a template node.
13177 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13178 * @return {HTMLElement} The node or null if it wasn't found
13180 getNode : function(nodeInfo){
13181 if(typeof nodeInfo == "string"){
13182 return document.getElementById(nodeInfo);
13183 }else if(typeof nodeInfo == "number"){
13184 return this.nodes[nodeInfo];
13190 * Gets a range template nodes.
13191 * @param {Number} startIndex
13192 * @param {Number} endIndex
13193 * @return {Array} An array of nodes
13195 getNodes : function(start, end){
13196 var ns = this.nodes;
13197 start = start || 0;
13198 end = typeof end == "undefined" ? ns.length - 1 : end;
13201 for(var i = start; i <= end; i++){
13205 for(var i = start; i >= end; i--){
13213 * Finds the index of the passed node
13214 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13215 * @return {Number} The index of the node or -1
13217 indexOf : function(node){
13218 node = this.getNode(node);
13219 if(typeof node.nodeIndex == "number"){
13220 return node.nodeIndex;
13222 var ns = this.nodes;
13223 for(var i = 0, len = ns.length; i < len; i++){
13234 * based on jquery fullcalendar
13238 Roo.bootstrap = Roo.bootstrap || {};
13240 * @class Roo.bootstrap.Calendar
13241 * @extends Roo.bootstrap.Component
13242 * Bootstrap Calendar class
13243 * @cfg {Boolean} loadMask (true|false) default false
13244 * @cfg {Object} header generate the user specific header of the calendar, default false
13247 * Create a new Container
13248 * @param {Object} config The config object
13253 Roo.bootstrap.Calendar = function(config){
13254 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13258 * Fires when a date is selected
13259 * @param {DatePicker} this
13260 * @param {Date} date The selected date
13264 * @event monthchange
13265 * Fires when the displayed month changes
13266 * @param {DatePicker} this
13267 * @param {Date} date The selected month
13269 'monthchange': true,
13271 * @event evententer
13272 * Fires when mouse over an event
13273 * @param {Calendar} this
13274 * @param {event} Event
13276 'evententer': true,
13278 * @event eventleave
13279 * Fires when the mouse leaves an
13280 * @param {Calendar} this
13283 'eventleave': true,
13285 * @event eventclick
13286 * Fires when the mouse click an
13287 * @param {Calendar} this
13296 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13299 * @cfg {Number} startDay
13300 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13308 getAutoCreate : function(){
13311 var fc_button = function(name, corner, style, content ) {
13312 return Roo.apply({},{
13314 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13316 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13319 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13330 style : 'width:100%',
13337 cls : 'fc-header-left',
13339 fc_button('prev', 'left', 'arrow', '‹' ),
13340 fc_button('next', 'right', 'arrow', '›' ),
13341 { tag: 'span', cls: 'fc-header-space' },
13342 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13350 cls : 'fc-header-center',
13354 cls: 'fc-header-title',
13357 html : 'month / year'
13365 cls : 'fc-header-right',
13367 /* fc_button('month', 'left', '', 'month' ),
13368 fc_button('week', '', '', 'week' ),
13369 fc_button('day', 'right', '', 'day' )
13381 header = this.header;
13384 var cal_heads = function() {
13386 // fixme - handle this.
13388 for (var i =0; i < Date.dayNames.length; i++) {
13389 var d = Date.dayNames[i];
13392 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13393 html : d.substring(0,3)
13397 ret[0].cls += ' fc-first';
13398 ret[6].cls += ' fc-last';
13401 var cal_cell = function(n) {
13404 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13409 cls: 'fc-day-number',
13413 cls: 'fc-day-content',
13417 style: 'position: relative;' // height: 17px;
13429 var cal_rows = function() {
13432 for (var r = 0; r < 6; r++) {
13439 for (var i =0; i < Date.dayNames.length; i++) {
13440 var d = Date.dayNames[i];
13441 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13444 row.cn[0].cls+=' fc-first';
13445 row.cn[0].cn[0].style = 'min-height:90px';
13446 row.cn[6].cls+=' fc-last';
13450 ret[0].cls += ' fc-first';
13451 ret[4].cls += ' fc-prev-last';
13452 ret[5].cls += ' fc-last';
13459 cls: 'fc-border-separate',
13460 style : 'width:100%',
13468 cls : 'fc-first fc-last',
13486 cls : 'fc-content',
13487 style : "position: relative;",
13490 cls : 'fc-view fc-view-month fc-grid',
13491 style : 'position: relative',
13492 unselectable : 'on',
13495 cls : 'fc-event-container',
13496 style : 'position:absolute;z-index:8;top:0;left:0;'
13514 initEvents : function()
13517 throw "can not find store for calendar";
13523 style: "text-align:center",
13527 style: "background-color:white;width:50%;margin:250 auto",
13531 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13542 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13544 var size = this.el.select('.fc-content', true).first().getSize();
13545 this.maskEl.setSize(size.width, size.height);
13546 this.maskEl.enableDisplayMode("block");
13547 if(!this.loadMask){
13548 this.maskEl.hide();
13551 this.store = Roo.factory(this.store, Roo.data);
13552 this.store.on('load', this.onLoad, this);
13553 this.store.on('beforeload', this.onBeforeLoad, this);
13557 this.cells = this.el.select('.fc-day',true);
13558 //Roo.log(this.cells);
13559 this.textNodes = this.el.query('.fc-day-number');
13560 this.cells.addClassOnOver('fc-state-hover');
13562 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13563 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13564 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13565 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13567 this.on('monthchange', this.onMonthChange, this);
13569 this.update(new Date().clearTime());
13572 resize : function() {
13573 var sz = this.el.getSize();
13575 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13576 this.el.select('.fc-day-content div',true).setHeight(34);
13581 showPrevMonth : function(e){
13582 this.update(this.activeDate.add("mo", -1));
13584 showToday : function(e){
13585 this.update(new Date().clearTime());
13588 showNextMonth : function(e){
13589 this.update(this.activeDate.add("mo", 1));
13593 showPrevYear : function(){
13594 this.update(this.activeDate.add("y", -1));
13598 showNextYear : function(){
13599 this.update(this.activeDate.add("y", 1));
13604 update : function(date)
13606 var vd = this.activeDate;
13607 this.activeDate = date;
13608 // if(vd && this.el){
13609 // var t = date.getTime();
13610 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13611 // Roo.log('using add remove');
13613 // this.fireEvent('monthchange', this, date);
13615 // this.cells.removeClass("fc-state-highlight");
13616 // this.cells.each(function(c){
13617 // if(c.dateValue == t){
13618 // c.addClass("fc-state-highlight");
13619 // setTimeout(function(){
13620 // try{c.dom.firstChild.focus();}catch(e){}
13630 var days = date.getDaysInMonth();
13632 var firstOfMonth = date.getFirstDateOfMonth();
13633 var startingPos = firstOfMonth.getDay()-this.startDay;
13635 if(startingPos < this.startDay){
13639 var pm = date.add(Date.MONTH, -1);
13640 var prevStart = pm.getDaysInMonth()-startingPos;
13642 this.cells = this.el.select('.fc-day',true);
13643 this.textNodes = this.el.query('.fc-day-number');
13644 this.cells.addClassOnOver('fc-state-hover');
13646 var cells = this.cells.elements;
13647 var textEls = this.textNodes;
13649 Roo.each(cells, function(cell){
13650 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13653 days += startingPos;
13655 // convert everything to numbers so it's fast
13656 var day = 86400000;
13657 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13660 //Roo.log(prevStart);
13662 var today = new Date().clearTime().getTime();
13663 var sel = date.clearTime().getTime();
13664 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13665 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13666 var ddMatch = this.disabledDatesRE;
13667 var ddText = this.disabledDatesText;
13668 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13669 var ddaysText = this.disabledDaysText;
13670 var format = this.format;
13672 var setCellClass = function(cal, cell){
13676 //Roo.log('set Cell Class');
13678 var t = d.getTime();
13682 cell.dateValue = t;
13684 cell.className += " fc-today";
13685 cell.className += " fc-state-highlight";
13686 cell.title = cal.todayText;
13689 // disable highlight in other month..
13690 //cell.className += " fc-state-highlight";
13695 cell.className = " fc-state-disabled";
13696 cell.title = cal.minText;
13700 cell.className = " fc-state-disabled";
13701 cell.title = cal.maxText;
13705 if(ddays.indexOf(d.getDay()) != -1){
13706 cell.title = ddaysText;
13707 cell.className = " fc-state-disabled";
13710 if(ddMatch && format){
13711 var fvalue = d.dateFormat(format);
13712 if(ddMatch.test(fvalue)){
13713 cell.title = ddText.replace("%0", fvalue);
13714 cell.className = " fc-state-disabled";
13718 if (!cell.initialClassName) {
13719 cell.initialClassName = cell.dom.className;
13722 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13727 for(; i < startingPos; i++) {
13728 textEls[i].innerHTML = (++prevStart);
13729 d.setDate(d.getDate()+1);
13731 cells[i].className = "fc-past fc-other-month";
13732 setCellClass(this, cells[i]);
13737 for(; i < days; i++){
13738 intDay = i - startingPos + 1;
13739 textEls[i].innerHTML = (intDay);
13740 d.setDate(d.getDate()+1);
13742 cells[i].className = ''; // "x-date-active";
13743 setCellClass(this, cells[i]);
13747 for(; i < 42; i++) {
13748 textEls[i].innerHTML = (++extraDays);
13749 d.setDate(d.getDate()+1);
13751 cells[i].className = "fc-future fc-other-month";
13752 setCellClass(this, cells[i]);
13755 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13757 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13759 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13760 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13762 if(totalRows != 6){
13763 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13764 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13767 this.fireEvent('monthchange', this, date);
13771 if(!this.internalRender){
13772 var main = this.el.dom.firstChild;
13773 var w = main.offsetWidth;
13774 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13775 Roo.fly(main).setWidth(w);
13776 this.internalRender = true;
13777 // opera does not respect the auto grow header center column
13778 // then, after it gets a width opera refuses to recalculate
13779 // without a second pass
13780 if(Roo.isOpera && !this.secondPass){
13781 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13782 this.secondPass = true;
13783 this.update.defer(10, this, [date]);
13790 findCell : function(dt) {
13791 dt = dt.clearTime().getTime();
13793 this.cells.each(function(c){
13794 //Roo.log("check " +c.dateValue + '?=' + dt);
13795 if(c.dateValue == dt){
13805 findCells : function(ev) {
13806 var s = ev.start.clone().clearTime().getTime();
13808 var e= ev.end.clone().clearTime().getTime();
13811 this.cells.each(function(c){
13812 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13814 if(c.dateValue > e){
13817 if(c.dateValue < s){
13826 // findBestRow: function(cells)
13830 // for (var i =0 ; i < cells.length;i++) {
13831 // ret = Math.max(cells[i].rows || 0,ret);
13838 addItem : function(ev)
13840 // look for vertical location slot in
13841 var cells = this.findCells(ev);
13843 // ev.row = this.findBestRow(cells);
13845 // work out the location.
13849 for(var i =0; i < cells.length; i++) {
13851 cells[i].row = cells[0].row;
13854 cells[i].row = cells[i].row + 1;
13864 if (crow.start.getY() == cells[i].getY()) {
13866 crow.end = cells[i];
13883 cells[0].events.push(ev);
13885 this.calevents.push(ev);
13888 clearEvents: function() {
13890 if(!this.calevents){
13894 Roo.each(this.cells.elements, function(c){
13900 Roo.each(this.calevents, function(e) {
13901 Roo.each(e.els, function(el) {
13902 el.un('mouseenter' ,this.onEventEnter, this);
13903 el.un('mouseleave' ,this.onEventLeave, this);
13908 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13914 renderEvents: function()
13918 this.cells.each(function(c) {
13927 if(c.row != c.events.length){
13928 r = 4 - (4 - (c.row - c.events.length));
13931 c.events = ev.slice(0, r);
13932 c.more = ev.slice(r);
13934 if(c.more.length && c.more.length == 1){
13935 c.events.push(c.more.pop());
13938 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13942 this.cells.each(function(c) {
13944 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13947 for (var e = 0; e < c.events.length; e++){
13948 var ev = c.events[e];
13949 var rows = ev.rows;
13951 for(var i = 0; i < rows.length; i++) {
13953 // how many rows should it span..
13956 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13957 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13959 unselectable : "on",
13962 cls: 'fc-event-inner',
13966 // cls: 'fc-event-time',
13967 // html : cells.length > 1 ? '' : ev.time
13971 cls: 'fc-event-title',
13972 html : String.format('{0}', ev.title)
13979 cls: 'ui-resizable-handle ui-resizable-e',
13980 html : '  '
13987 cfg.cls += ' fc-event-start';
13989 if ((i+1) == rows.length) {
13990 cfg.cls += ' fc-event-end';
13993 var ctr = _this.el.select('.fc-event-container',true).first();
13994 var cg = ctr.createChild(cfg);
13996 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13997 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13999 var r = (c.more.length) ? 1 : 0;
14000 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14001 cg.setWidth(ebox.right - sbox.x -2);
14003 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14004 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14005 cg.on('click', _this.onEventClick, _this, ev);
14016 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14017 style : 'position: absolute',
14018 unselectable : "on",
14021 cls: 'fc-event-inner',
14025 cls: 'fc-event-title',
14033 cls: 'ui-resizable-handle ui-resizable-e',
14034 html : '  '
14040 var ctr = _this.el.select('.fc-event-container',true).first();
14041 var cg = ctr.createChild(cfg);
14043 var sbox = c.select('.fc-day-content',true).first().getBox();
14044 var ebox = c.select('.fc-day-content',true).first().getBox();
14046 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14047 cg.setWidth(ebox.right - sbox.x -2);
14049 cg.on('click', _this.onMoreEventClick, _this, c.more);
14059 onEventEnter: function (e, el,event,d) {
14060 this.fireEvent('evententer', this, el, event);
14063 onEventLeave: function (e, el,event,d) {
14064 this.fireEvent('eventleave', this, el, event);
14067 onEventClick: function (e, el,event,d) {
14068 this.fireEvent('eventclick', this, el, event);
14071 onMonthChange: function () {
14075 onMoreEventClick: function(e, el, more)
14079 this.calpopover.placement = 'right';
14080 this.calpopover.setTitle('More');
14082 this.calpopover.setContent('');
14084 var ctr = this.calpopover.el.select('.popover-content', true).first();
14086 Roo.each(more, function(m){
14088 cls : 'fc-event-hori fc-event-draggable',
14091 var cg = ctr.createChild(cfg);
14093 cg.on('click', _this.onEventClick, _this, m);
14096 this.calpopover.show(el);
14101 onLoad: function ()
14103 this.calevents = [];
14106 if(this.store.getCount() > 0){
14107 this.store.data.each(function(d){
14110 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14111 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14112 time : d.data.start_time,
14113 title : d.data.title,
14114 description : d.data.description,
14115 venue : d.data.venue
14120 this.renderEvents();
14122 if(this.calevents.length && this.loadMask){
14123 this.maskEl.hide();
14127 onBeforeLoad: function()
14129 this.clearEvents();
14131 this.maskEl.show();
14145 * @class Roo.bootstrap.Popover
14146 * @extends Roo.bootstrap.Component
14147 * Bootstrap Popover class
14148 * @cfg {String} html contents of the popover (or false to use children..)
14149 * @cfg {String} title of popover (or false to hide)
14150 * @cfg {String} placement how it is placed
14151 * @cfg {String} trigger click || hover (or false to trigger manually)
14152 * @cfg {String} over what (parent or false to trigger manually.)
14153 * @cfg {Number} delay - delay before showing
14156 * Create a new Popover
14157 * @param {Object} config The config object
14160 Roo.bootstrap.Popover = function(config){
14161 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14164 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14166 title: 'Fill in a title',
14169 placement : 'right',
14170 trigger : 'hover', // hover
14176 can_build_overlaid : false,
14178 getChildContainer : function()
14180 return this.el.select('.popover-content',true).first();
14183 getAutoCreate : function(){
14184 Roo.log('make popover?');
14186 cls : 'popover roo-dynamic',
14187 style: 'display:block',
14193 cls : 'popover-inner',
14197 cls: 'popover-title',
14201 cls : 'popover-content',
14212 setTitle: function(str)
14214 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14216 setContent: function(str)
14218 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14220 // as it get's added to the bottom of the page.
14221 onRender : function(ct, position)
14223 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14225 var cfg = Roo.apply({}, this.getAutoCreate());
14229 cfg.cls += ' ' + this.cls;
14232 cfg.style = this.style;
14234 Roo.log("adding to ")
14235 this.el = Roo.get(document.body).createChild(cfg, position);
14241 initEvents : function()
14243 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14244 this.el.enableDisplayMode('block');
14246 if (this.over === false) {
14249 if (this.triggers === false) {
14252 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14253 var triggers = this.trigger ? this.trigger.split(' ') : [];
14254 Roo.each(triggers, function(trigger) {
14256 if (trigger == 'click') {
14257 on_el.on('click', this.toggle, this);
14258 } else if (trigger != 'manual') {
14259 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14260 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14262 on_el.on(eventIn ,this.enter, this);
14263 on_el.on(eventOut, this.leave, this);
14274 toggle : function () {
14275 this.hoverState == 'in' ? this.leave() : this.enter();
14278 enter : function () {
14281 clearTimeout(this.timeout);
14283 this.hoverState = 'in';
14285 if (!this.delay || !this.delay.show) {
14290 this.timeout = setTimeout(function () {
14291 if (_t.hoverState == 'in') {
14294 }, this.delay.show)
14296 leave : function() {
14297 clearTimeout(this.timeout);
14299 this.hoverState = 'out';
14301 if (!this.delay || !this.delay.hide) {
14306 this.timeout = setTimeout(function () {
14307 if (_t.hoverState == 'out') {
14310 }, this.delay.hide)
14313 show : function (on_el)
14316 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14319 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14320 if (this.html !== false) {
14321 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14323 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14324 if (!this.title.length) {
14325 this.el.select('.popover-title',true).hide();
14328 var placement = typeof this.placement == 'function' ?
14329 this.placement.call(this, this.el, on_el) :
14332 var autoToken = /\s?auto?\s?/i;
14333 var autoPlace = autoToken.test(placement);
14335 placement = placement.replace(autoToken, '') || 'top';
14339 //this.el.setXY([0,0]);
14341 this.el.dom.style.display='block';
14342 this.el.addClass(placement);
14344 //this.el.appendTo(on_el);
14346 var p = this.getPosition();
14347 var box = this.el.getBox();
14352 var align = Roo.bootstrap.Popover.alignment[placement];
14353 this.el.alignTo(on_el, align[0],align[1]);
14354 //var arrow = this.el.select('.arrow',true).first();
14355 //arrow.set(align[2],
14357 this.el.addClass('in');
14358 this.hoverState = null;
14360 if (this.el.hasClass('fade')) {
14367 this.el.setXY([0,0]);
14368 this.el.removeClass('in');
14375 Roo.bootstrap.Popover.alignment = {
14376 'left' : ['r-l', [-10,0], 'right'],
14377 'right' : ['l-r', [10,0], 'left'],
14378 'bottom' : ['t-b', [0,10], 'top'],
14379 'top' : [ 'b-t', [0,-10], 'bottom']
14390 * @class Roo.bootstrap.Progress
14391 * @extends Roo.bootstrap.Component
14392 * Bootstrap Progress class
14393 * @cfg {Boolean} striped striped of the progress bar
14394 * @cfg {Boolean} active animated of the progress bar
14398 * Create a new Progress
14399 * @param {Object} config The config object
14402 Roo.bootstrap.Progress = function(config){
14403 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14406 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14411 getAutoCreate : function(){
14419 cfg.cls += ' progress-striped';
14423 cfg.cls += ' active';
14442 * @class Roo.bootstrap.ProgressBar
14443 * @extends Roo.bootstrap.Component
14444 * Bootstrap ProgressBar class
14445 * @cfg {Number} aria_valuenow aria-value now
14446 * @cfg {Number} aria_valuemin aria-value min
14447 * @cfg {Number} aria_valuemax aria-value max
14448 * @cfg {String} label label for the progress bar
14449 * @cfg {String} panel (success | info | warning | danger )
14450 * @cfg {String} role role of the progress bar
14451 * @cfg {String} sr_only text
14455 * Create a new ProgressBar
14456 * @param {Object} config The config object
14459 Roo.bootstrap.ProgressBar = function(config){
14460 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14463 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14467 aria_valuemax : 100,
14473 getAutoCreate : function()
14478 cls: 'progress-bar',
14479 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14491 cfg.role = this.role;
14494 if(this.aria_valuenow){
14495 cfg['aria-valuenow'] = this.aria_valuenow;
14498 if(this.aria_valuemin){
14499 cfg['aria-valuemin'] = this.aria_valuemin;
14502 if(this.aria_valuemax){
14503 cfg['aria-valuemax'] = this.aria_valuemax;
14506 if(this.label && !this.sr_only){
14507 cfg.html = this.label;
14511 cfg.cls += ' progress-bar-' + this.panel;
14517 update : function(aria_valuenow)
14519 this.aria_valuenow = aria_valuenow;
14521 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14536 * @class Roo.bootstrap.TabGroup
14537 * @extends Roo.bootstrap.Column
14538 * Bootstrap Column class
14539 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14540 * @cfg {Boolean} carousel true to make the group behave like a carousel
14543 * Create a new TabGroup
14544 * @param {Object} config The config object
14547 Roo.bootstrap.TabGroup = function(config){
14548 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14550 this.navId = Roo.id();
14553 Roo.bootstrap.TabGroup.register(this);
14557 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14560 transition : false,
14562 getAutoCreate : function()
14564 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14566 cfg.cls += ' tab-content';
14568 if (this.carousel) {
14569 cfg.cls += ' carousel slide';
14571 cls : 'carousel-inner'
14578 getChildContainer : function()
14580 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14584 * register a Navigation item
14585 * @param {Roo.bootstrap.NavItem} the navitem to add
14587 register : function(item)
14589 this.tabs.push( item);
14590 item.navId = this.navId; // not really needed..
14594 getActivePanel : function()
14597 Roo.each(this.tabs, function(t) {
14607 getPanelByName : function(n)
14610 Roo.each(this.tabs, function(t) {
14611 if (t.tabId == n) {
14619 indexOfPanel : function(p)
14622 Roo.each(this.tabs, function(t,i) {
14623 if (t.tabId == p.tabId) {
14632 * show a specific panel
14633 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14634 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14636 showPanel : function (pan)
14639 if (typeof(pan) == 'number') {
14640 pan = this.tabs[pan];
14642 if (typeof(pan) == 'string') {
14643 pan = this.getPanelByName(pan);
14645 if (pan.tabId == this.getActivePanel().tabId) {
14648 var cur = this.getActivePanel();
14650 if (false === cur.fireEvent('beforedeactivate')) {
14654 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14656 this.transition = true;
14657 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14658 var lr = dir == 'next' ? 'left' : 'right';
14659 pan.el.addClass(dir); // or prev
14660 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14661 cur.el.addClass(lr); // or right
14662 pan.el.addClass(lr);
14665 cur.el.on('transitionend', function() {
14666 Roo.log("trans end?");
14668 pan.el.removeClass([lr,dir]);
14669 pan.setActive(true);
14671 cur.el.removeClass([lr]);
14672 cur.setActive(false);
14674 _this.transition = false;
14676 }, this, { single: true } );
14680 cur.setActive(false);
14681 pan.setActive(true);
14685 showPanelNext : function()
14687 var i = this.indexOfPanel(this.getActivePanel());
14688 if (i > this.tabs.length) {
14691 this.showPanel(this.tabs[i+1]);
14693 showPanelPrev : function()
14695 var i = this.indexOfPanel(this.getActivePanel());
14699 this.showPanel(this.tabs[i-1]);
14710 Roo.apply(Roo.bootstrap.TabGroup, {
14714 * register a Navigation Group
14715 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14717 register : function(navgrp)
14719 this.groups[navgrp.navId] = navgrp;
14723 * fetch a Navigation Group based on the navigation ID
14724 * if one does not exist , it will get created.
14725 * @param {string} the navgroup to add
14726 * @returns {Roo.bootstrap.NavGroup} the navgroup
14728 get: function(navId) {
14729 if (typeof(this.groups[navId]) == 'undefined') {
14730 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14732 return this.groups[navId] ;
14747 * @class Roo.bootstrap.TabPanel
14748 * @extends Roo.bootstrap.Component
14749 * Bootstrap TabPanel class
14750 * @cfg {Boolean} active panel active
14751 * @cfg {String} html panel content
14752 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14753 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14757 * Create a new TabPanel
14758 * @param {Object} config The config object
14761 Roo.bootstrap.TabPanel = function(config){
14762 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14766 * Fires when the active status changes
14767 * @param {Roo.bootstrap.TabPanel} this
14768 * @param {Boolean} state the new state
14773 * @event beforedeactivate
14774 * Fires before a tab is de-activated - can be used to do validation on a form.
14775 * @param {Roo.bootstrap.TabPanel} this
14776 * @return {Boolean} false if there is an error
14779 'beforedeactivate': true
14782 this.tabId = this.tabId || Roo.id();
14786 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14793 getAutoCreate : function(){
14796 // item is needed for carousel - not sure if it has any effect otherwise
14797 cls: 'tab-pane item',
14798 html: this.html || ''
14802 cfg.cls += ' active';
14806 cfg.tabId = this.tabId;
14813 initEvents: function()
14815 Roo.log('-------- init events on tab panel ---------');
14817 var p = this.parent();
14818 this.navId = this.navId || p.navId;
14820 if (typeof(this.navId) != 'undefined') {
14821 // not really needed.. but just in case.. parent should be a NavGroup.
14822 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14823 Roo.log(['register', tg, this]);
14829 onRender : function(ct, position)
14831 // Roo.log("Call onRender: " + this.xtype);
14833 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14841 setActive: function(state)
14843 Roo.log("panel - set active " + this.tabId + "=" + state);
14845 this.active = state;
14847 this.el.removeClass('active');
14849 } else if (!this.el.hasClass('active')) {
14850 this.el.addClass('active');
14852 this.fireEvent('changed', this, state);
14869 * @class Roo.bootstrap.DateField
14870 * @extends Roo.bootstrap.Input
14871 * Bootstrap DateField class
14872 * @cfg {Number} weekStart default 0
14873 * @cfg {String} viewMode default empty, (months|years)
14874 * @cfg {String} minViewMode default empty, (months|years)
14875 * @cfg {Number} startDate default -Infinity
14876 * @cfg {Number} endDate default Infinity
14877 * @cfg {Boolean} todayHighlight default false
14878 * @cfg {Boolean} todayBtn default false
14879 * @cfg {Boolean} calendarWeeks default false
14880 * @cfg {Object} daysOfWeekDisabled default empty
14881 * @cfg {Boolean} singleMode default false (true | false)
14883 * @cfg {Boolean} keyboardNavigation default true
14884 * @cfg {String} language default en
14887 * Create a new DateField
14888 * @param {Object} config The config object
14891 Roo.bootstrap.DateField = function(config){
14892 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14896 * Fires when this field show.
14897 * @param {Roo.bootstrap.DateField} this
14898 * @param {Mixed} date The date value
14903 * Fires when this field hide.
14904 * @param {Roo.bootstrap.DateField} this
14905 * @param {Mixed} date The date value
14910 * Fires when select a date.
14911 * @param {Roo.bootstrap.DateField} this
14912 * @param {Mixed} date The date value
14918 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14921 * @cfg {String} format
14922 * The default date format string which can be overriden for localization support. The format must be
14923 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14927 * @cfg {String} altFormats
14928 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14929 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14931 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14939 todayHighlight : false,
14945 keyboardNavigation: true,
14947 calendarWeeks: false,
14949 startDate: -Infinity,
14953 daysOfWeekDisabled: [],
14957 singleMode : false,
14959 UTCDate: function()
14961 return new Date(Date.UTC.apply(Date, arguments));
14964 UTCToday: function()
14966 var today = new Date();
14967 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14970 getDate: function() {
14971 var d = this.getUTCDate();
14972 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14975 getUTCDate: function() {
14979 setDate: function(d) {
14980 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14983 setUTCDate: function(d) {
14985 this.setValue(this.formatDate(this.date));
14988 onRender: function(ct, position)
14991 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14993 this.language = this.language || 'en';
14994 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14995 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14997 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14998 this.format = this.format || 'm/d/y';
14999 this.isInline = false;
15000 this.isInput = true;
15001 this.component = this.el.select('.add-on', true).first() || false;
15002 this.component = (this.component && this.component.length === 0) ? false : this.component;
15003 this.hasInput = this.component && this.inputEL().length;
15005 if (typeof(this.minViewMode === 'string')) {
15006 switch (this.minViewMode) {
15008 this.minViewMode = 1;
15011 this.minViewMode = 2;
15014 this.minViewMode = 0;
15019 if (typeof(this.viewMode === 'string')) {
15020 switch (this.viewMode) {
15033 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15035 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15037 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15039 this.picker().on('mousedown', this.onMousedown, this);
15040 this.picker().on('click', this.onClick, this);
15042 this.picker().addClass('datepicker-dropdown');
15044 this.startViewMode = this.viewMode;
15046 if(this.singleMode){
15047 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15048 v.setVisibilityMode(Roo.Element.DISPLAY)
15052 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15053 v.setStyle('width', '189px');
15057 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15058 if(!this.calendarWeeks){
15063 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15064 v.attr('colspan', function(i, val){
15065 return parseInt(val) + 1;
15070 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15072 this.setStartDate(this.startDate);
15073 this.setEndDate(this.endDate);
15075 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15082 if(this.isInline) {
15087 picker : function()
15089 return this.pickerEl;
15090 // return this.el.select('.datepicker', true).first();
15093 fillDow: function()
15095 var dowCnt = this.weekStart;
15104 if(this.calendarWeeks){
15112 while (dowCnt < this.weekStart + 7) {
15116 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15120 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15123 fillMonths: function()
15126 var months = this.picker().select('>.datepicker-months td', true).first();
15128 months.dom.innerHTML = '';
15134 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15137 months.createChild(month);
15144 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;
15146 if (this.date < this.startDate) {
15147 this.viewDate = new Date(this.startDate);
15148 } else if (this.date > this.endDate) {
15149 this.viewDate = new Date(this.endDate);
15151 this.viewDate = new Date(this.date);
15159 var d = new Date(this.viewDate),
15160 year = d.getUTCFullYear(),
15161 month = d.getUTCMonth(),
15162 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15163 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15164 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15165 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15166 currentDate = this.date && this.date.valueOf(),
15167 today = this.UTCToday();
15169 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15171 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15173 // this.picker.select('>tfoot th.today').
15174 // .text(dates[this.language].today)
15175 // .toggle(this.todayBtn !== false);
15177 this.updateNavArrows();
15180 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15182 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15184 prevMonth.setUTCDate(day);
15186 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15188 var nextMonth = new Date(prevMonth);
15190 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15192 nextMonth = nextMonth.valueOf();
15194 var fillMonths = false;
15196 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15198 while(prevMonth.valueOf() < nextMonth) {
15201 if (prevMonth.getUTCDay() === this.weekStart) {
15203 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15211 if(this.calendarWeeks){
15212 // ISO 8601: First week contains first thursday.
15213 // ISO also states week starts on Monday, but we can be more abstract here.
15215 // Start of current week: based on weekstart/current date
15216 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15217 // Thursday of this week
15218 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15219 // First Thursday of year, year from thursday
15220 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15221 // Calendar week: ms between thursdays, div ms per day, div 7 days
15222 calWeek = (th - yth) / 864e5 / 7 + 1;
15224 fillMonths.cn.push({
15232 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15234 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15237 if (this.todayHighlight &&
15238 prevMonth.getUTCFullYear() == today.getFullYear() &&
15239 prevMonth.getUTCMonth() == today.getMonth() &&
15240 prevMonth.getUTCDate() == today.getDate()) {
15241 clsName += ' today';
15244 if (currentDate && prevMonth.valueOf() === currentDate) {
15245 clsName += ' active';
15248 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15249 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15250 clsName += ' disabled';
15253 fillMonths.cn.push({
15255 cls: 'day ' + clsName,
15256 html: prevMonth.getDate()
15259 prevMonth.setDate(prevMonth.getDate()+1);
15262 var currentYear = this.date && this.date.getUTCFullYear();
15263 var currentMonth = this.date && this.date.getUTCMonth();
15265 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15267 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15268 v.removeClass('active');
15270 if(currentYear === year && k === currentMonth){
15271 v.addClass('active');
15274 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15275 v.addClass('disabled');
15281 year = parseInt(year/10, 10) * 10;
15283 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15285 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15288 for (var i = -1; i < 11; i++) {
15289 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15291 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15299 showMode: function(dir)
15302 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15305 Roo.each(this.picker().select('>div',true).elements, function(v){
15306 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15309 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15314 if(this.isInline) return;
15316 this.picker().removeClass(['bottom', 'top']);
15318 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15320 * place to the top of element!
15324 this.picker().addClass('top');
15325 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15330 this.picker().addClass('bottom');
15332 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15335 parseDate : function(value)
15337 if(!value || value instanceof Date){
15340 var v = Date.parseDate(value, this.format);
15341 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15342 v = Date.parseDate(value, 'Y-m-d');
15344 if(!v && this.altFormats){
15345 if(!this.altFormatsArray){
15346 this.altFormatsArray = this.altFormats.split("|");
15348 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15349 v = Date.parseDate(value, this.altFormatsArray[i]);
15355 formatDate : function(date, fmt)
15357 return (!date || !(date instanceof Date)) ?
15358 date : date.dateFormat(fmt || this.format);
15361 onFocus : function()
15363 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15367 onBlur : function()
15369 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15371 var d = this.inputEl().getValue();
15380 this.picker().show();
15384 this.fireEvent('show', this, this.date);
15389 if(this.isInline) return;
15390 this.picker().hide();
15391 this.viewMode = this.startViewMode;
15394 this.fireEvent('hide', this, this.date);
15398 onMousedown: function(e)
15400 e.stopPropagation();
15401 e.preventDefault();
15406 Roo.bootstrap.DateField.superclass.keyup.call(this);
15410 setValue: function(v)
15413 // v can be a string or a date..
15416 var d = new Date(this.parseDate(v) ).clearTime();
15418 if(isNaN(d.getTime())){
15419 this.date = this.viewDate = '';
15420 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15424 v = this.formatDate(d);
15426 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15428 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15432 this.fireEvent('select', this, this.date);
15436 getValue: function()
15438 return this.formatDate(this.date);
15441 fireKey: function(e)
15443 if (!this.picker().isVisible()){
15444 if (e.keyCode == 27) // allow escape to hide and re-show picker
15449 var dateChanged = false,
15451 newDate, newViewDate;
15456 e.preventDefault();
15460 if (!this.keyboardNavigation) break;
15461 dir = e.keyCode == 37 ? -1 : 1;
15464 newDate = this.moveYear(this.date, dir);
15465 newViewDate = this.moveYear(this.viewDate, dir);
15466 } else if (e.shiftKey){
15467 newDate = this.moveMonth(this.date, dir);
15468 newViewDate = this.moveMonth(this.viewDate, dir);
15470 newDate = new Date(this.date);
15471 newDate.setUTCDate(this.date.getUTCDate() + dir);
15472 newViewDate = new Date(this.viewDate);
15473 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15475 if (this.dateWithinRange(newDate)){
15476 this.date = newDate;
15477 this.viewDate = newViewDate;
15478 this.setValue(this.formatDate(this.date));
15480 e.preventDefault();
15481 dateChanged = true;
15486 if (!this.keyboardNavigation) break;
15487 dir = e.keyCode == 38 ? -1 : 1;
15489 newDate = this.moveYear(this.date, dir);
15490 newViewDate = this.moveYear(this.viewDate, dir);
15491 } else if (e.shiftKey){
15492 newDate = this.moveMonth(this.date, dir);
15493 newViewDate = this.moveMonth(this.viewDate, dir);
15495 newDate = new Date(this.date);
15496 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15497 newViewDate = new Date(this.viewDate);
15498 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15500 if (this.dateWithinRange(newDate)){
15501 this.date = newDate;
15502 this.viewDate = newViewDate;
15503 this.setValue(this.formatDate(this.date));
15505 e.preventDefault();
15506 dateChanged = true;
15510 this.setValue(this.formatDate(this.date));
15512 e.preventDefault();
15515 this.setValue(this.formatDate(this.date));
15529 onClick: function(e)
15531 e.stopPropagation();
15532 e.preventDefault();
15534 var target = e.getTarget();
15536 if(target.nodeName.toLowerCase() === 'i'){
15537 target = Roo.get(target).dom.parentNode;
15540 var nodeName = target.nodeName;
15541 var className = target.className;
15542 var html = target.innerHTML;
15543 //Roo.log(nodeName);
15545 switch(nodeName.toLowerCase()) {
15547 switch(className) {
15553 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15554 switch(this.viewMode){
15556 this.viewDate = this.moveMonth(this.viewDate, dir);
15560 this.viewDate = this.moveYear(this.viewDate, dir);
15566 var date = new Date();
15567 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15569 this.setValue(this.formatDate(this.date));
15576 if (className.indexOf('disabled') < 0) {
15577 this.viewDate.setUTCDate(1);
15578 if (className.indexOf('month') > -1) {
15579 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15581 var year = parseInt(html, 10) || 0;
15582 this.viewDate.setUTCFullYear(year);
15586 if(this.singleMode){
15587 this.setValue(this.formatDate(this.viewDate));
15598 //Roo.log(className);
15599 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15600 var day = parseInt(html, 10) || 1;
15601 var year = this.viewDate.getUTCFullYear(),
15602 month = this.viewDate.getUTCMonth();
15604 if (className.indexOf('old') > -1) {
15611 } else if (className.indexOf('new') > -1) {
15619 //Roo.log([year,month,day]);
15620 this.date = this.UTCDate(year, month, day,0,0,0,0);
15621 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15623 //Roo.log(this.formatDate(this.date));
15624 this.setValue(this.formatDate(this.date));
15631 setStartDate: function(startDate)
15633 this.startDate = startDate || -Infinity;
15634 if (this.startDate !== -Infinity) {
15635 this.startDate = this.parseDate(this.startDate);
15638 this.updateNavArrows();
15641 setEndDate: function(endDate)
15643 this.endDate = endDate || Infinity;
15644 if (this.endDate !== Infinity) {
15645 this.endDate = this.parseDate(this.endDate);
15648 this.updateNavArrows();
15651 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15653 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15654 if (typeof(this.daysOfWeekDisabled) !== 'object') {
15655 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15657 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15658 return parseInt(d, 10);
15661 this.updateNavArrows();
15664 updateNavArrows: function()
15666 if(this.singleMode){
15670 var d = new Date(this.viewDate),
15671 year = d.getUTCFullYear(),
15672 month = d.getUTCMonth();
15674 Roo.each(this.picker().select('.prev', true).elements, function(v){
15676 switch (this.viewMode) {
15679 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15685 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15692 Roo.each(this.picker().select('.next', true).elements, function(v){
15694 switch (this.viewMode) {
15697 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15703 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15711 moveMonth: function(date, dir)
15713 if (!dir) return date;
15714 var new_date = new Date(date.valueOf()),
15715 day = new_date.getUTCDate(),
15716 month = new_date.getUTCMonth(),
15717 mag = Math.abs(dir),
15719 dir = dir > 0 ? 1 : -1;
15722 // If going back one month, make sure month is not current month
15723 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15725 return new_date.getUTCMonth() == month;
15727 // If going forward one month, make sure month is as expected
15728 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15730 return new_date.getUTCMonth() != new_month;
15732 new_month = month + dir;
15733 new_date.setUTCMonth(new_month);
15734 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15735 if (new_month < 0 || new_month > 11)
15736 new_month = (new_month + 12) % 12;
15738 // For magnitudes >1, move one month at a time...
15739 for (var i=0; i<mag; i++)
15740 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15741 new_date = this.moveMonth(new_date, dir);
15742 // ...then reset the day, keeping it in the new month
15743 new_month = new_date.getUTCMonth();
15744 new_date.setUTCDate(day);
15746 return new_month != new_date.getUTCMonth();
15749 // Common date-resetting loop -- if date is beyond end of month, make it
15752 new_date.setUTCDate(--day);
15753 new_date.setUTCMonth(new_month);
15758 moveYear: function(date, dir)
15760 return this.moveMonth(date, dir*12);
15763 dateWithinRange: function(date)
15765 return date >= this.startDate && date <= this.endDate;
15771 this.picker().remove();
15776 Roo.apply(Roo.bootstrap.DateField, {
15787 html: '<i class="fa fa-arrow-left"/>'
15797 html: '<i class="fa fa-arrow-right"/>'
15839 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15840 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15841 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15842 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15843 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15856 navFnc: 'FullYear',
15861 navFnc: 'FullYear',
15866 Roo.apply(Roo.bootstrap.DateField, {
15870 cls: 'datepicker dropdown-menu roo-dynamic',
15874 cls: 'datepicker-days',
15878 cls: 'table-condensed',
15880 Roo.bootstrap.DateField.head,
15884 Roo.bootstrap.DateField.footer
15891 cls: 'datepicker-months',
15895 cls: 'table-condensed',
15897 Roo.bootstrap.DateField.head,
15898 Roo.bootstrap.DateField.content,
15899 Roo.bootstrap.DateField.footer
15906 cls: 'datepicker-years',
15910 cls: 'table-condensed',
15912 Roo.bootstrap.DateField.head,
15913 Roo.bootstrap.DateField.content,
15914 Roo.bootstrap.DateField.footer
15933 * @class Roo.bootstrap.TimeField
15934 * @extends Roo.bootstrap.Input
15935 * Bootstrap DateField class
15939 * Create a new TimeField
15940 * @param {Object} config The config object
15943 Roo.bootstrap.TimeField = function(config){
15944 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15948 * Fires when this field show.
15949 * @param {Roo.bootstrap.DateField} thisthis
15950 * @param {Mixed} date The date value
15955 * Fires when this field hide.
15956 * @param {Roo.bootstrap.DateField} this
15957 * @param {Mixed} date The date value
15962 * Fires when select a date.
15963 * @param {Roo.bootstrap.DateField} this
15964 * @param {Mixed} date The date value
15970 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15973 * @cfg {String} format
15974 * The default time format string which can be overriden for localization support. The format must be
15975 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15979 onRender: function(ct, position)
15982 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15984 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15986 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15988 this.pop = this.picker().select('>.datepicker-time',true).first();
15989 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15991 this.picker().on('mousedown', this.onMousedown, this);
15992 this.picker().on('click', this.onClick, this);
15994 this.picker().addClass('datepicker-dropdown');
15999 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16000 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16001 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16002 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16003 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16004 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16008 fireKey: function(e){
16009 if (!this.picker().isVisible()){
16010 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16016 e.preventDefault();
16024 this.onTogglePeriod();
16027 this.onIncrementMinutes();
16030 this.onDecrementMinutes();
16039 onClick: function(e) {
16040 e.stopPropagation();
16041 e.preventDefault();
16044 picker : function()
16046 return this.el.select('.datepicker', true).first();
16049 fillTime: function()
16051 var time = this.pop.select('tbody', true).first();
16053 time.dom.innerHTML = '';
16068 cls: 'hours-up glyphicon glyphicon-chevron-up'
16088 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16109 cls: 'timepicker-hour',
16124 cls: 'timepicker-minute',
16139 cls: 'btn btn-primary period',
16161 cls: 'hours-down glyphicon glyphicon-chevron-down'
16181 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16199 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16206 var hours = this.time.getHours();
16207 var minutes = this.time.getMinutes();
16220 hours = hours - 12;
16224 hours = '0' + hours;
16228 minutes = '0' + minutes;
16231 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16232 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16233 this.pop.select('button', true).first().dom.innerHTML = period;
16239 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16241 var cls = ['bottom'];
16243 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16250 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16255 this.picker().addClass(cls.join('-'));
16259 Roo.each(cls, function(c){
16261 _this.picker().setTop(_this.inputEl().getHeight());
16265 _this.picker().setTop(0 - _this.picker().getHeight());
16270 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16274 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16281 onFocus : function()
16283 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16287 onBlur : function()
16289 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16295 this.picker().show();
16300 this.fireEvent('show', this, this.date);
16305 this.picker().hide();
16308 this.fireEvent('hide', this, this.date);
16311 setTime : function()
16314 this.setValue(this.time.format(this.format));
16316 this.fireEvent('select', this, this.date);
16321 onMousedown: function(e){
16322 e.stopPropagation();
16323 e.preventDefault();
16326 onIncrementHours: function()
16328 Roo.log('onIncrementHours');
16329 this.time = this.time.add(Date.HOUR, 1);
16334 onDecrementHours: function()
16336 Roo.log('onDecrementHours');
16337 this.time = this.time.add(Date.HOUR, -1);
16341 onIncrementMinutes: function()
16343 Roo.log('onIncrementMinutes');
16344 this.time = this.time.add(Date.MINUTE, 1);
16348 onDecrementMinutes: function()
16350 Roo.log('onDecrementMinutes');
16351 this.time = this.time.add(Date.MINUTE, -1);
16355 onTogglePeriod: function()
16357 Roo.log('onTogglePeriod');
16358 this.time = this.time.add(Date.HOUR, 12);
16365 Roo.apply(Roo.bootstrap.TimeField, {
16395 cls: 'btn btn-info ok',
16407 Roo.apply(Roo.bootstrap.TimeField, {
16411 cls: 'datepicker dropdown-menu',
16415 cls: 'datepicker-time',
16419 cls: 'table-condensed',
16421 Roo.bootstrap.TimeField.content,
16422 Roo.bootstrap.TimeField.footer
16441 * @class Roo.bootstrap.MonthField
16442 * @extends Roo.bootstrap.Input
16443 * Bootstrap MonthField class
16445 * @cfg {String} language default en
16448 * Create a new MonthField
16449 * @param {Object} config The config object
16452 Roo.bootstrap.MonthField = function(config){
16453 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16458 * Fires when this field show.
16459 * @param {Roo.bootstrap.MonthField} this
16460 * @param {Mixed} date The date value
16465 * Fires when this field hide.
16466 * @param {Roo.bootstrap.MonthField} this
16467 * @param {Mixed} date The date value
16472 * Fires when select a date.
16473 * @param {Roo.bootstrap.MonthField} this
16474 * @param {String} oldvalue The old value
16475 * @param {String} newvalue The new value
16481 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16483 onRender: function(ct, position)
16486 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16488 this.language = this.language || 'en';
16489 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16490 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16492 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16493 this.isInline = false;
16494 this.isInput = true;
16495 this.component = this.el.select('.add-on', true).first() || false;
16496 this.component = (this.component && this.component.length === 0) ? false : this.component;
16497 this.hasInput = this.component && this.inputEL().length;
16499 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16501 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16503 this.picker().on('mousedown', this.onMousedown, this);
16504 this.picker().on('click', this.onClick, this);
16506 this.picker().addClass('datepicker-dropdown');
16508 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16509 v.setStyle('width', '189px');
16516 if(this.isInline) {
16522 setValue: function(v, suppressEvent)
16524 var o = this.getValue();
16526 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16530 if(suppressEvent !== true){
16531 this.fireEvent('select', this, o, v);
16536 getValue: function()
16541 onClick: function(e)
16543 e.stopPropagation();
16544 e.preventDefault();
16546 var target = e.getTarget();
16548 if(target.nodeName.toLowerCase() === 'i'){
16549 target = Roo.get(target).dom.parentNode;
16552 var nodeName = target.nodeName;
16553 var className = target.className;
16554 var html = target.innerHTML;
16556 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16560 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16562 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16568 picker : function()
16570 return this.pickerEl;
16573 fillMonths: function()
16576 var months = this.picker().select('>.datepicker-months td', true).first();
16578 months.dom.innerHTML = '';
16584 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16587 months.createChild(month);
16596 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16597 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16600 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16601 e.removeClass('active');
16603 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16604 e.addClass('active');
16611 if(this.isInline) return;
16613 this.picker().removeClass(['bottom', 'top']);
16615 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16617 * place to the top of element!
16621 this.picker().addClass('top');
16622 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16627 this.picker().addClass('bottom');
16629 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16632 onFocus : function()
16634 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16638 onBlur : function()
16640 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16642 var d = this.inputEl().getValue();
16651 this.picker().show();
16652 this.picker().select('>.datepicker-months', true).first().show();
16656 this.fireEvent('show', this, this.date);
16661 if(this.isInline) return;
16662 this.picker().hide();
16663 this.fireEvent('hide', this, this.date);
16667 onMousedown: function(e)
16669 e.stopPropagation();
16670 e.preventDefault();
16675 Roo.bootstrap.MonthField.superclass.keyup.call(this);
16679 fireKey: function(e)
16681 if (!this.picker().isVisible()){
16682 if (e.keyCode == 27) // allow escape to hide and re-show picker
16692 e.preventDefault();
16696 dir = e.keyCode == 37 ? -1 : 1;
16698 this.vIndex = this.vIndex + dir;
16700 if(this.vIndex < 0){
16704 if(this.vIndex > 11){
16708 if(isNaN(this.vIndex)){
16712 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16718 dir = e.keyCode == 38 ? -1 : 1;
16720 this.vIndex = this.vIndex + dir * 4;
16722 if(this.vIndex < 0){
16726 if(this.vIndex > 11){
16730 if(isNaN(this.vIndex)){
16734 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16739 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16740 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16744 e.preventDefault();
16747 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16748 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16764 this.picker().remove();
16769 Roo.apply(Roo.bootstrap.MonthField, {
16788 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16789 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16794 Roo.apply(Roo.bootstrap.MonthField, {
16798 cls: 'datepicker dropdown-menu roo-dynamic',
16802 cls: 'datepicker-months',
16806 cls: 'table-condensed',
16808 Roo.bootstrap.DateField.content
16828 * @class Roo.bootstrap.CheckBox
16829 * @extends Roo.bootstrap.Input
16830 * Bootstrap CheckBox class
16832 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16833 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16834 * @cfg {String} boxLabel The text that appears beside the checkbox
16835 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16836 * @cfg {Boolean} checked initnal the element
16837 * @cfg {Boolean} inline inline the element (default false)
16838 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16841 * Create a new CheckBox
16842 * @param {Object} config The config object
16845 Roo.bootstrap.CheckBox = function(config){
16846 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16851 * Fires when the element is checked or unchecked.
16852 * @param {Roo.bootstrap.CheckBox} this This input
16853 * @param {Boolean} checked The new checked value
16860 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
16862 inputType: 'checkbox',
16870 getAutoCreate : function()
16872 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16878 cfg.cls = 'form-group ' + this.inputType; //input-group
16881 cfg.cls += ' ' + this.inputType + '-inline';
16887 type : this.inputType,
16888 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16889 cls : 'roo-' + this.inputType, //'form-box',
16890 placeholder : this.placeholder || ''
16894 if (this.weight) { // Validity check?
16895 cfg.cls += " " + this.inputType + "-" + this.weight;
16898 if (this.disabled) {
16899 input.disabled=true;
16903 input.checked = this.checked;
16907 input.name = this.name;
16911 input.cls += ' input-' + this.size;
16916 ['xs','sm','md','lg'].map(function(size){
16917 if (settings[size]) {
16918 cfg.cls += ' col-' + size + '-' + settings[size];
16922 var inputblock = input;
16924 if (this.before || this.after) {
16927 cls : 'input-group',
16932 inputblock.cn.push({
16934 cls : 'input-group-addon',
16939 inputblock.cn.push(input);
16942 inputblock.cn.push({
16944 cls : 'input-group-addon',
16951 if (align ==='left' && this.fieldLabel.length) {
16952 Roo.log("left and has label");
16958 cls : 'control-label col-md-' + this.labelWidth,
16959 html : this.fieldLabel
16963 cls : "col-md-" + (12 - this.labelWidth),
16970 } else if ( this.fieldLabel.length) {
16975 tag: this.boxLabel ? 'span' : 'label',
16977 cls: 'control-label box-input-label',
16978 //cls : 'input-group-addon',
16979 html : this.fieldLabel
16989 Roo.log(" no label && no align");
16990 cfg.cn = [ inputblock ] ;
16995 var boxLabelCfg = {
16997 //'for': id, // box label is handled by onclick - so no for...
16999 html: this.boxLabel
17003 boxLabelCfg.tooltip = this.tooltip;
17006 cfg.cn.push(boxLabelCfg);
17016 * return the real input element.
17018 inputEl: function ()
17020 return this.el.select('input.roo-' + this.inputType,true).first();
17023 labelEl: function()
17025 return this.el.select('label.control-label',true).first();
17027 /* depricated... */
17031 return this.labelEl();
17034 initEvents : function()
17036 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17038 this.inputEl().on('click', this.onClick, this);
17040 if (this.boxLabel) {
17041 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17044 this.startValue = this.getValue();
17047 Roo.bootstrap.CheckBox.register(this);
17051 onClick : function()
17053 this.setChecked(!this.checked);
17056 setChecked : function(state,suppressEvent)
17058 this.startValue = this.getValue();
17060 if(this.inputType == 'radio'){
17062 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17063 e.dom.checked = false;
17066 this.inputEl().dom.checked = true;
17068 this.inputEl().dom.value = this.inputValue;
17070 if(suppressEvent !== true){
17071 this.fireEvent('check', this, true);
17079 this.checked = state;
17081 this.inputEl().dom.checked = state;
17083 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17085 if(suppressEvent !== true){
17086 this.fireEvent('check', this, state);
17092 getValue : function()
17094 if(this.inputType == 'radio'){
17095 return this.getGroupValue();
17098 return this.inputEl().getValue();
17102 getGroupValue : function()
17104 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17108 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17111 setValue : function(v,suppressEvent)
17113 if(this.inputType == 'radio'){
17114 this.setGroupValue(v, suppressEvent);
17118 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17123 setGroupValue : function(v, suppressEvent)
17125 this.startValue = this.getValue();
17127 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17128 e.dom.checked = false;
17130 if(e.dom.value == v){
17131 e.dom.checked = true;
17135 if(suppressEvent !== true){
17136 this.fireEvent('check', this, true);
17144 validate : function()
17148 (this.inputType == 'radio' && this.validateRadio()) ||
17149 (this.inputType == 'checkbox' && this.validateCheckbox())
17155 this.markInvalid();
17159 validateRadio : function()
17163 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17164 if(!e.dom.checked){
17176 validateCheckbox : function()
17179 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17182 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17190 for(var i in group){
17195 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17202 * Mark this field as valid
17204 markValid : function()
17206 if(this.allowBlank){
17212 this.fireEvent('valid', this);
17214 if(this.inputType == 'radio'){
17215 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17216 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17217 e.findParent('.form-group', false, true).addClass(_this.validClass);
17224 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17225 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17229 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17235 for(var i in group){
17236 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17237 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17242 * Mark this field as invalid
17243 * @param {String} msg The validation message
17245 markInvalid : function(msg)
17247 if(this.allowBlank){
17253 this.fireEvent('invalid', this, msg);
17255 if(this.inputType == 'radio'){
17256 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17257 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17258 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17265 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17266 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17270 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17276 for(var i in group){
17277 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17278 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17285 Roo.apply(Roo.bootstrap.CheckBox, {
17290 * register a CheckBox Group
17291 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17293 register : function(checkbox)
17295 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17296 this.groups[checkbox.groupId] = {};
17299 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17303 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17307 * fetch a CheckBox Group based on the group ID
17308 * @param {string} the group ID
17309 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17311 get: function(groupId) {
17312 if (typeof(this.groups[groupId]) == 'undefined') {
17316 return this.groups[groupId] ;
17328 *<div class="radio">
17330 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17331 Option one is this and that—be sure to include why it's great
17338 *<label class="radio-inline">fieldLabel</label>
17339 *<label class="radio-inline">
17340 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17348 * @class Roo.bootstrap.Radio
17349 * @extends Roo.bootstrap.CheckBox
17350 * Bootstrap Radio class
17353 * Create a new Radio
17354 * @param {Object} config The config object
17357 Roo.bootstrap.Radio = function(config){
17358 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17362 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17364 inputType: 'radio',
17368 getAutoCreate : function()
17370 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17371 align = align || 'left'; // default...
17378 tag : this.inline ? 'span' : 'div',
17383 var inline = this.inline ? ' radio-inline' : '';
17387 // does not need for, as we wrap the input with it..
17389 cls : 'control-label box-label' + inline,
17392 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17396 //cls : 'control-label' + inline,
17397 html : this.fieldLabel,
17398 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17407 type : this.inputType,
17408 //value : (!this.checked) ? this.valueOff : this.inputValue,
17409 value : this.inputValue,
17411 placeholder : this.placeholder || '' // ?? needed????
17414 if (this.weight) { // Validity check?
17415 input.cls += " radio-" + this.weight;
17417 if (this.disabled) {
17418 input.disabled=true;
17422 input.checked = this.checked;
17426 input.name = this.name;
17430 input.cls += ' input-' + this.size;
17433 //?? can span's inline have a width??
17436 ['xs','sm','md','lg'].map(function(size){
17437 if (settings[size]) {
17438 cfg.cls += ' col-' + size + '-' + settings[size];
17442 var inputblock = input;
17444 if (this.before || this.after) {
17447 cls : 'input-group',
17452 inputblock.cn.push({
17454 cls : 'input-group-addon',
17458 inputblock.cn.push(input);
17460 inputblock.cn.push({
17462 cls : 'input-group-addon',
17470 if (this.fieldLabel && this.fieldLabel.length) {
17471 cfg.cn.push(fieldLabel);
17474 // normal bootstrap puts the input inside the label.
17475 // however with our styled version - it has to go after the input.
17477 //lbl.cn.push(inputblock);
17481 cls: 'radio' + inline,
17488 cfg.cn.push( lblwrap);
17493 html: this.boxLabel
17502 initEvents : function()
17504 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17506 this.inputEl().on('click', this.onClick, this);
17507 if (this.boxLabel) {
17508 Roo.log('find label')
17509 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17514 inputEl: function ()
17516 return this.el.select('input.roo-radio',true).first();
17518 onClick : function()
17521 this.setChecked(true);
17524 setChecked : function(state,suppressEvent)
17527 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17528 v.dom.checked = false;
17531 Roo.log(this.inputEl().dom);
17532 this.checked = state;
17533 this.inputEl().dom.checked = state;
17535 if(suppressEvent !== true){
17536 this.fireEvent('check', this, state);
17539 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17543 getGroupValue : function()
17546 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17547 if(v.dom.checked == true){
17548 value = v.dom.value;
17556 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17557 * @return {Mixed} value The field value
17559 getValue : function(){
17560 return this.getGroupValue();
17566 //<script type="text/javascript">
17569 * Based Ext JS Library 1.1.1
17570 * Copyright(c) 2006-2007, Ext JS, LLC.
17576 * @class Roo.HtmlEditorCore
17577 * @extends Roo.Component
17578 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17580 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17583 Roo.HtmlEditorCore = function(config){
17586 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17591 * @event initialize
17592 * Fires when the editor is fully initialized (including the iframe)
17593 * @param {Roo.HtmlEditorCore} this
17598 * Fires when the editor is first receives the focus. Any insertion must wait
17599 * until after this event.
17600 * @param {Roo.HtmlEditorCore} this
17604 * @event beforesync
17605 * Fires before the textarea is updated with content from the editor iframe. Return false
17606 * to cancel the sync.
17607 * @param {Roo.HtmlEditorCore} this
17608 * @param {String} html
17612 * @event beforepush
17613 * Fires before the iframe editor is updated with content from the textarea. Return false
17614 * to cancel the push.
17615 * @param {Roo.HtmlEditorCore} this
17616 * @param {String} html
17621 * Fires when the textarea is updated with content from the editor iframe.
17622 * @param {Roo.HtmlEditorCore} this
17623 * @param {String} html
17628 * Fires when the iframe editor is updated with content from the textarea.
17629 * @param {Roo.HtmlEditorCore} this
17630 * @param {String} html
17635 * @event editorevent
17636 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17637 * @param {Roo.HtmlEditorCore} this
17643 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17645 // defaults : white / black...
17646 this.applyBlacklists();
17653 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
17657 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
17663 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17668 * @cfg {Number} height (in pixels)
17672 * @cfg {Number} width (in pixels)
17677 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17680 stylesheets: false,
17685 // private properties
17686 validationEvent : false,
17688 initialized : false,
17690 sourceEditMode : false,
17691 onFocus : Roo.emptyFn,
17693 hideMode:'offsets',
17697 // blacklist + whitelisted elements..
17704 * Protected method that will not generally be called directly. It
17705 * is called when the editor initializes the iframe with HTML contents. Override this method if you
17706 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17708 getDocMarkup : function(){
17712 // inherit styels from page...??
17713 if (this.stylesheets === false) {
17715 Roo.get(document.head).select('style').each(function(node) {
17716 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17719 Roo.get(document.head).select('link').each(function(node) {
17720 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17723 } else if (!this.stylesheets.length) {
17725 st = '<style type="text/css">' +
17726 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17732 st += '<style type="text/css">' +
17733 'IMG { cursor: pointer } ' +
17737 return '<html><head>' + st +
17738 //<style type="text/css">' +
17739 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17741 ' </head><body class="roo-htmleditor-body"></body></html>';
17745 onRender : function(ct, position)
17748 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17749 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17752 this.el.dom.style.border = '0 none';
17753 this.el.dom.setAttribute('tabIndex', -1);
17754 this.el.addClass('x-hidden hide');
17758 if(Roo.isIE){ // fix IE 1px bogus margin
17759 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17763 this.frameId = Roo.id();
17767 var iframe = this.owner.wrap.createChild({
17769 cls: 'form-control', // bootstrap..
17771 name: this.frameId,
17772 frameBorder : 'no',
17773 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
17778 this.iframe = iframe.dom;
17780 this.assignDocWin();
17782 this.doc.designMode = 'on';
17785 this.doc.write(this.getDocMarkup());
17789 var task = { // must defer to wait for browser to be ready
17791 //console.log("run task?" + this.doc.readyState);
17792 this.assignDocWin();
17793 if(this.doc.body || this.doc.readyState == 'complete'){
17795 this.doc.designMode="on";
17799 Roo.TaskMgr.stop(task);
17800 this.initEditor.defer(10, this);
17807 Roo.TaskMgr.start(task);
17812 onResize : function(w, h)
17814 Roo.log('resize: ' +w + ',' + h );
17815 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17819 if(typeof w == 'number'){
17821 this.iframe.style.width = w + 'px';
17823 if(typeof h == 'number'){
17825 this.iframe.style.height = h + 'px';
17827 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17834 * Toggles the editor between standard and source edit mode.
17835 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17837 toggleSourceEdit : function(sourceEditMode){
17839 this.sourceEditMode = sourceEditMode === true;
17841 if(this.sourceEditMode){
17843 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
17846 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17847 //this.iframe.className = '';
17850 //this.setSize(this.owner.wrap.getSize());
17851 //this.fireEvent('editmodechange', this, this.sourceEditMode);
17858 * Protected method that will not generally be called directly. If you need/want
17859 * custom HTML cleanup, this is the method you should override.
17860 * @param {String} html The HTML to be cleaned
17861 * return {String} The cleaned HTML
17863 cleanHtml : function(html){
17864 html = String(html);
17865 if(html.length > 5){
17866 if(Roo.isSafari){ // strip safari nonsense
17867 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17870 if(html == ' '){
17877 * HTML Editor -> Textarea
17878 * Protected method that will not generally be called directly. Syncs the contents
17879 * of the editor iframe with the textarea.
17881 syncValue : function(){
17882 if(this.initialized){
17883 var bd = (this.doc.body || this.doc.documentElement);
17884 //this.cleanUpPaste(); -- this is done else where and causes havoc..
17885 var html = bd.innerHTML;
17887 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17888 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17890 html = '<div style="'+m[0]+'">' + html + '</div>';
17893 html = this.cleanHtml(html);
17894 // fix up the special chars.. normaly like back quotes in word...
17895 // however we do not want to do this with chinese..
17896 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17897 var cc = b.charCodeAt();
17899 (cc >= 0x4E00 && cc < 0xA000 ) ||
17900 (cc >= 0x3400 && cc < 0x4E00 ) ||
17901 (cc >= 0xf900 && cc < 0xfb00 )
17907 if(this.owner.fireEvent('beforesync', this, html) !== false){
17908 this.el.dom.value = html;
17909 this.owner.fireEvent('sync', this, html);
17915 * Protected method that will not generally be called directly. Pushes the value of the textarea
17916 * into the iframe editor.
17918 pushValue : function(){
17919 if(this.initialized){
17920 var v = this.el.dom.value.trim();
17922 // if(v.length < 1){
17926 if(this.owner.fireEvent('beforepush', this, v) !== false){
17927 var d = (this.doc.body || this.doc.documentElement);
17929 this.cleanUpPaste();
17930 this.el.dom.value = d.innerHTML;
17931 this.owner.fireEvent('push', this, v);
17937 deferFocus : function(){
17938 this.focus.defer(10, this);
17942 focus : function(){
17943 if(this.win && !this.sourceEditMode){
17950 assignDocWin: function()
17952 var iframe = this.iframe;
17955 this.doc = iframe.contentWindow.document;
17956 this.win = iframe.contentWindow;
17958 // if (!Roo.get(this.frameId)) {
17961 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17962 // this.win = Roo.get(this.frameId).dom.contentWindow;
17964 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17968 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17969 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17974 initEditor : function(){
17975 //console.log("INIT EDITOR");
17976 this.assignDocWin();
17980 this.doc.designMode="on";
17982 this.doc.write(this.getDocMarkup());
17985 var dbody = (this.doc.body || this.doc.documentElement);
17986 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17987 // this copies styles from the containing element into thsi one..
17988 // not sure why we need all of this..
17989 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17991 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17992 //ss['background-attachment'] = 'fixed'; // w3c
17993 dbody.bgProperties = 'fixed'; // ie
17994 //Roo.DomHelper.applyStyles(dbody, ss);
17995 Roo.EventManager.on(this.doc, {
17996 //'mousedown': this.onEditorEvent,
17997 'mouseup': this.onEditorEvent,
17998 'dblclick': this.onEditorEvent,
17999 'click': this.onEditorEvent,
18000 'keyup': this.onEditorEvent,
18005 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18007 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18008 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18010 this.initialized = true;
18012 this.owner.fireEvent('initialize', this);
18017 onDestroy : function(){
18023 //for (var i =0; i < this.toolbars.length;i++) {
18024 // // fixme - ask toolbars for heights?
18025 // this.toolbars[i].onDestroy();
18028 //this.wrap.dom.innerHTML = '';
18029 //this.wrap.remove();
18034 onFirstFocus : function(){
18036 this.assignDocWin();
18039 this.activated = true;
18042 if(Roo.isGecko){ // prevent silly gecko errors
18044 var s = this.win.getSelection();
18045 if(!s.focusNode || s.focusNode.nodeType != 3){
18046 var r = s.getRangeAt(0);
18047 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18052 this.execCmd('useCSS', true);
18053 this.execCmd('styleWithCSS', false);
18056 this.owner.fireEvent('activate', this);
18060 adjustFont: function(btn){
18061 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18062 //if(Roo.isSafari){ // safari
18065 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18066 if(Roo.isSafari){ // safari
18067 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18068 v = (v < 10) ? 10 : v;
18069 v = (v > 48) ? 48 : v;
18070 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18075 v = Math.max(1, v+adjust);
18077 this.execCmd('FontSize', v );
18080 onEditorEvent : function(e){
18081 this.owner.fireEvent('editorevent', this, e);
18082 // this.updateToolbar();
18083 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18086 insertTag : function(tg)
18088 // could be a bit smarter... -> wrap the current selected tRoo..
18089 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18091 range = this.createRange(this.getSelection());
18092 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18093 wrappingNode.appendChild(range.extractContents());
18094 range.insertNode(wrappingNode);
18101 this.execCmd("formatblock", tg);
18105 insertText : function(txt)
18109 var range = this.createRange();
18110 range.deleteContents();
18111 //alert(Sender.getAttribute('label'));
18113 range.insertNode(this.doc.createTextNode(txt));
18119 * Executes a Midas editor command on the editor document and performs necessary focus and
18120 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18121 * @param {String} cmd The Midas command
18122 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18124 relayCmd : function(cmd, value){
18126 this.execCmd(cmd, value);
18127 this.owner.fireEvent('editorevent', this);
18128 //this.updateToolbar();
18129 this.owner.deferFocus();
18133 * Executes a Midas editor command directly on the editor document.
18134 * For visual commands, you should use {@link #relayCmd} instead.
18135 * <b>This should only be called after the editor is initialized.</b>
18136 * @param {String} cmd The Midas command
18137 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18139 execCmd : function(cmd, value){
18140 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18147 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18149 * @param {String} text | dom node..
18151 insertAtCursor : function(text)
18156 if(!this.activated){
18162 var r = this.doc.selection.createRange();
18173 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18177 // from jquery ui (MIT licenced)
18179 var win = this.win;
18181 if (win.getSelection && win.getSelection().getRangeAt) {
18182 range = win.getSelection().getRangeAt(0);
18183 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18184 range.insertNode(node);
18185 } else if (win.document.selection && win.document.selection.createRange) {
18186 // no firefox support
18187 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18188 win.document.selection.createRange().pasteHTML(txt);
18190 // no firefox support
18191 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18192 this.execCmd('InsertHTML', txt);
18201 mozKeyPress : function(e){
18203 var c = e.getCharCode(), cmd;
18206 c = String.fromCharCode(c).toLowerCase();
18220 this.cleanUpPaste.defer(100, this);
18228 e.preventDefault();
18236 fixKeys : function(){ // load time branching for fastest keydown performance
18238 return function(e){
18239 var k = e.getKey(), r;
18242 r = this.doc.selection.createRange();
18245 r.pasteHTML('    ');
18252 r = this.doc.selection.createRange();
18254 var target = r.parentElement();
18255 if(!target || target.tagName.toLowerCase() != 'li'){
18257 r.pasteHTML('<br />');
18263 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18264 this.cleanUpPaste.defer(100, this);
18270 }else if(Roo.isOpera){
18271 return function(e){
18272 var k = e.getKey();
18276 this.execCmd('InsertHTML','    ');
18279 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18280 this.cleanUpPaste.defer(100, this);
18285 }else if(Roo.isSafari){
18286 return function(e){
18287 var k = e.getKey();
18291 this.execCmd('InsertText','\t');
18295 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18296 this.cleanUpPaste.defer(100, this);
18304 getAllAncestors: function()
18306 var p = this.getSelectedNode();
18309 a.push(p); // push blank onto stack..
18310 p = this.getParentElement();
18314 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18318 a.push(this.doc.body);
18322 lastSelNode : false,
18325 getSelection : function()
18327 this.assignDocWin();
18328 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18331 getSelectedNode: function()
18333 // this may only work on Gecko!!!
18335 // should we cache this!!!!
18340 var range = this.createRange(this.getSelection()).cloneRange();
18343 var parent = range.parentElement();
18345 var testRange = range.duplicate();
18346 testRange.moveToElementText(parent);
18347 if (testRange.inRange(range)) {
18350 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18353 parent = parent.parentElement;
18358 // is ancestor a text element.
18359 var ac = range.commonAncestorContainer;
18360 if (ac.nodeType == 3) {
18361 ac = ac.parentNode;
18364 var ar = ac.childNodes;
18367 var other_nodes = [];
18368 var has_other_nodes = false;
18369 for (var i=0;i<ar.length;i++) {
18370 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18373 // fullly contained node.
18375 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18380 // probably selected..
18381 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18382 other_nodes.push(ar[i]);
18386 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18391 has_other_nodes = true;
18393 if (!nodes.length && other_nodes.length) {
18394 nodes= other_nodes;
18396 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18402 createRange: function(sel)
18404 // this has strange effects when using with
18405 // top toolbar - not sure if it's a great idea.
18406 //this.editor.contentWindow.focus();
18407 if (typeof sel != "undefined") {
18409 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18411 return this.doc.createRange();
18414 return this.doc.createRange();
18417 getParentElement: function()
18420 this.assignDocWin();
18421 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18423 var range = this.createRange(sel);
18426 var p = range.commonAncestorContainer;
18427 while (p.nodeType == 3) { // text node
18438 * Range intersection.. the hard stuff...
18442 * [ -- selected range --- ]
18446 * if end is before start or hits it. fail.
18447 * if start is after end or hits it fail.
18449 * if either hits (but other is outside. - then it's not
18455 // @see http://www.thismuchiknow.co.uk/?p=64.
18456 rangeIntersectsNode : function(range, node)
18458 var nodeRange = node.ownerDocument.createRange();
18460 nodeRange.selectNode(node);
18462 nodeRange.selectNodeContents(node);
18465 var rangeStartRange = range.cloneRange();
18466 rangeStartRange.collapse(true);
18468 var rangeEndRange = range.cloneRange();
18469 rangeEndRange.collapse(false);
18471 var nodeStartRange = nodeRange.cloneRange();
18472 nodeStartRange.collapse(true);
18474 var nodeEndRange = nodeRange.cloneRange();
18475 nodeEndRange.collapse(false);
18477 return rangeStartRange.compareBoundaryPoints(
18478 Range.START_TO_START, nodeEndRange) == -1 &&
18479 rangeEndRange.compareBoundaryPoints(
18480 Range.START_TO_START, nodeStartRange) == 1;
18484 rangeCompareNode : function(range, node)
18486 var nodeRange = node.ownerDocument.createRange();
18488 nodeRange.selectNode(node);
18490 nodeRange.selectNodeContents(node);
18494 range.collapse(true);
18496 nodeRange.collapse(true);
18498 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18499 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18501 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18503 var nodeIsBefore = ss == 1;
18504 var nodeIsAfter = ee == -1;
18506 if (nodeIsBefore && nodeIsAfter)
18508 if (!nodeIsBefore && nodeIsAfter)
18509 return 1; //right trailed.
18511 if (nodeIsBefore && !nodeIsAfter)
18512 return 2; // left trailed.
18517 // private? - in a new class?
18518 cleanUpPaste : function()
18520 // cleans up the whole document..
18521 Roo.log('cleanuppaste');
18523 this.cleanUpChildren(this.doc.body);
18524 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18525 if (clean != this.doc.body.innerHTML) {
18526 this.doc.body.innerHTML = clean;
18531 cleanWordChars : function(input) {// change the chars to hex code
18532 var he = Roo.HtmlEditorCore;
18534 var output = input;
18535 Roo.each(he.swapCodes, function(sw) {
18536 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18538 output = output.replace(swapper, sw[1]);
18545 cleanUpChildren : function (n)
18547 if (!n.childNodes.length) {
18550 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18551 this.cleanUpChild(n.childNodes[i]);
18558 cleanUpChild : function (node)
18561 //console.log(node);
18562 if (node.nodeName == "#text") {
18563 // clean up silly Windows -- stuff?
18566 if (node.nodeName == "#comment") {
18567 node.parentNode.removeChild(node);
18568 // clean up silly Windows -- stuff?
18571 var lcname = node.tagName.toLowerCase();
18572 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18573 // whitelist of tags..
18575 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18577 node.parentNode.removeChild(node);
18582 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18584 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18585 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18587 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18588 // remove_keep_children = true;
18591 if (remove_keep_children) {
18592 this.cleanUpChildren(node);
18593 // inserts everything just before this node...
18594 while (node.childNodes.length) {
18595 var cn = node.childNodes[0];
18596 node.removeChild(cn);
18597 node.parentNode.insertBefore(cn, node);
18599 node.parentNode.removeChild(node);
18603 if (!node.attributes || !node.attributes.length) {
18604 this.cleanUpChildren(node);
18608 function cleanAttr(n,v)
18611 if (v.match(/^\./) || v.match(/^\//)) {
18614 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18617 if (v.match(/^#/)) {
18620 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18621 node.removeAttribute(n);
18625 var cwhite = this.cwhite;
18626 var cblack = this.cblack;
18628 function cleanStyle(n,v)
18630 if (v.match(/expression/)) { //XSS?? should we even bother..
18631 node.removeAttribute(n);
18635 var parts = v.split(/;/);
18638 Roo.each(parts, function(p) {
18639 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18643 var l = p.split(':').shift().replace(/\s+/g,'');
18644 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18646 if ( cwhite.length && cblack.indexOf(l) > -1) {
18647 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18648 //node.removeAttribute(n);
18652 // only allow 'c whitelisted system attributes'
18653 if ( cwhite.length && cwhite.indexOf(l) < 0) {
18654 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18655 //node.removeAttribute(n);
18665 if (clean.length) {
18666 node.setAttribute(n, clean.join(';'));
18668 node.removeAttribute(n);
18674 for (var i = node.attributes.length-1; i > -1 ; i--) {
18675 var a = node.attributes[i];
18678 if (a.name.toLowerCase().substr(0,2)=='on') {
18679 node.removeAttribute(a.name);
18682 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18683 node.removeAttribute(a.name);
18686 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18687 cleanAttr(a.name,a.value); // fixme..
18690 if (a.name == 'style') {
18691 cleanStyle(a.name,a.value);
18694 /// clean up MS crap..
18695 // tecnically this should be a list of valid class'es..
18698 if (a.name == 'class') {
18699 if (a.value.match(/^Mso/)) {
18700 node.className = '';
18703 if (a.value.match(/body/)) {
18704 node.className = '';
18715 this.cleanUpChildren(node);
18720 * Clean up MS wordisms...
18722 cleanWord : function(node)
18725 var cleanWordChildren = function()
18727 if (!node.childNodes.length) {
18730 for (var i = node.childNodes.length-1; i > -1 ; i--) {
18731 _t.cleanWord(node.childNodes[i]);
18737 this.cleanWord(this.doc.body);
18740 if (node.nodeName == "#text") {
18741 // clean up silly Windows -- stuff?
18744 if (node.nodeName == "#comment") {
18745 node.parentNode.removeChild(node);
18746 // clean up silly Windows -- stuff?
18750 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18751 node.parentNode.removeChild(node);
18755 // remove - but keep children..
18756 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18757 while (node.childNodes.length) {
18758 var cn = node.childNodes[0];
18759 node.removeChild(cn);
18760 node.parentNode.insertBefore(cn, node);
18762 node.parentNode.removeChild(node);
18763 cleanWordChildren();
18767 if (node.className.length) {
18769 var cn = node.className.split(/\W+/);
18771 Roo.each(cn, function(cls) {
18772 if (cls.match(/Mso[a-zA-Z]+/)) {
18777 node.className = cna.length ? cna.join(' ') : '';
18779 node.removeAttribute("class");
18783 if (node.hasAttribute("lang")) {
18784 node.removeAttribute("lang");
18787 if (node.hasAttribute("style")) {
18789 var styles = node.getAttribute("style").split(";");
18791 Roo.each(styles, function(s) {
18792 if (!s.match(/:/)) {
18795 var kv = s.split(":");
18796 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18799 // what ever is left... we allow.
18802 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18803 if (!nstyle.length) {
18804 node.removeAttribute('style');
18808 cleanWordChildren();
18812 domToHTML : function(currentElement, depth, nopadtext) {
18814 depth = depth || 0;
18815 nopadtext = nopadtext || false;
18817 if (!currentElement) {
18818 return this.domToHTML(this.doc.body);
18821 //Roo.log(currentElement);
18823 var allText = false;
18824 var nodeName = currentElement.nodeName;
18825 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18827 if (nodeName == '#text') {
18829 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18834 if (nodeName != 'BODY') {
18837 // Prints the node tagName, such as <A>, <IMG>, etc
18840 for(i = 0; i < currentElement.attributes.length;i++) {
18842 var aname = currentElement.attributes.item(i).name;
18843 if (!currentElement.attributes.item(i).value.length) {
18846 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18849 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18858 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18861 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18866 // Traverse the tree
18868 var currentElementChild = currentElement.childNodes.item(i);
18869 var allText = true;
18870 var innerHTML = '';
18872 while (currentElementChild) {
18873 // Formatting code (indent the tree so it looks nice on the screen)
18874 var nopad = nopadtext;
18875 if (lastnode == 'SPAN') {
18879 if (currentElementChild.nodeName == '#text') {
18880 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18881 toadd = nopadtext ? toadd : toadd.trim();
18882 if (!nopad && toadd.length > 80) {
18883 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
18885 innerHTML += toadd;
18888 currentElementChild = currentElement.childNodes.item(i);
18894 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
18896 // Recursively traverse the tree structure of the child node
18897 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
18898 lastnode = currentElementChild.nodeName;
18900 currentElementChild=currentElement.childNodes.item(i);
18906 // The remaining code is mostly for formatting the tree
18907 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
18912 ret+= "</"+tagName+">";
18918 applyBlacklists : function()
18920 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
18921 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
18925 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18926 if (b.indexOf(tag) > -1) {
18929 this.white.push(tag);
18933 Roo.each(w, function(tag) {
18934 if (b.indexOf(tag) > -1) {
18937 if (this.white.indexOf(tag) > -1) {
18940 this.white.push(tag);
18945 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18946 if (w.indexOf(tag) > -1) {
18949 this.black.push(tag);
18953 Roo.each(b, function(tag) {
18954 if (w.indexOf(tag) > -1) {
18957 if (this.black.indexOf(tag) > -1) {
18960 this.black.push(tag);
18965 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
18966 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
18970 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18971 if (b.indexOf(tag) > -1) {
18974 this.cwhite.push(tag);
18978 Roo.each(w, function(tag) {
18979 if (b.indexOf(tag) > -1) {
18982 if (this.cwhite.indexOf(tag) > -1) {
18985 this.cwhite.push(tag);
18990 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18991 if (w.indexOf(tag) > -1) {
18994 this.cblack.push(tag);
18998 Roo.each(b, function(tag) {
18999 if (w.indexOf(tag) > -1) {
19002 if (this.cblack.indexOf(tag) > -1) {
19005 this.cblack.push(tag);
19010 setStylesheets : function(stylesheets)
19012 if(typeof(stylesheets) == 'string'){
19013 Roo.get(this.iframe.contentDocument.head).createChild({
19015 rel : 'stylesheet',
19024 Roo.each(stylesheets, function(s) {
19029 Roo.get(_this.iframe.contentDocument.head).createChild({
19031 rel : 'stylesheet',
19040 removeStylesheets : function()
19044 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19049 // hide stuff that is not compatible
19063 * @event specialkey
19067 * @cfg {String} fieldClass @hide
19070 * @cfg {String} focusClass @hide
19073 * @cfg {String} autoCreate @hide
19076 * @cfg {String} inputType @hide
19079 * @cfg {String} invalidClass @hide
19082 * @cfg {String} invalidText @hide
19085 * @cfg {String} msgFx @hide
19088 * @cfg {String} validateOnBlur @hide
19092 Roo.HtmlEditorCore.white = [
19093 'area', 'br', 'img', 'input', 'hr', 'wbr',
19095 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19096 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19097 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19098 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19099 'table', 'ul', 'xmp',
19101 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19104 'dir', 'menu', 'ol', 'ul', 'dl',
19110 Roo.HtmlEditorCore.black = [
19111 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19113 'base', 'basefont', 'bgsound', 'blink', 'body',
19114 'frame', 'frameset', 'head', 'html', 'ilayer',
19115 'iframe', 'layer', 'link', 'meta', 'object',
19116 'script', 'style' ,'title', 'xml' // clean later..
19118 Roo.HtmlEditorCore.clean = [
19119 'script', 'style', 'title', 'xml'
19121 Roo.HtmlEditorCore.remove = [
19126 Roo.HtmlEditorCore.ablack = [
19130 Roo.HtmlEditorCore.aclean = [
19131 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19135 Roo.HtmlEditorCore.pwhite= [
19136 'http', 'https', 'mailto'
19139 // white listed style attributes.
19140 Roo.HtmlEditorCore.cwhite= [
19141 // 'text-align', /// default is to allow most things..
19147 // black listed style attributes.
19148 Roo.HtmlEditorCore.cblack= [
19149 // 'font-size' -- this can be set by the project
19153 Roo.HtmlEditorCore.swapCodes =[
19172 * @class Roo.bootstrap.HtmlEditor
19173 * @extends Roo.bootstrap.TextArea
19174 * Bootstrap HtmlEditor class
19177 * Create a new HtmlEditor
19178 * @param {Object} config The config object
19181 Roo.bootstrap.HtmlEditor = function(config){
19182 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19183 if (!this.toolbars) {
19184 this.toolbars = [];
19186 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19189 * @event initialize
19190 * Fires when the editor is fully initialized (including the iframe)
19191 * @param {HtmlEditor} this
19196 * Fires when the editor is first receives the focus. Any insertion must wait
19197 * until after this event.
19198 * @param {HtmlEditor} this
19202 * @event beforesync
19203 * Fires before the textarea is updated with content from the editor iframe. Return false
19204 * to cancel the sync.
19205 * @param {HtmlEditor} this
19206 * @param {String} html
19210 * @event beforepush
19211 * Fires before the iframe editor is updated with content from the textarea. Return false
19212 * to cancel the push.
19213 * @param {HtmlEditor} this
19214 * @param {String} html
19219 * Fires when the textarea is updated with content from the editor iframe.
19220 * @param {HtmlEditor} this
19221 * @param {String} html
19226 * Fires when the iframe editor is updated with content from the textarea.
19227 * @param {HtmlEditor} this
19228 * @param {String} html
19232 * @event editmodechange
19233 * Fires when the editor switches edit modes
19234 * @param {HtmlEditor} this
19235 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19237 editmodechange: true,
19239 * @event editorevent
19240 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19241 * @param {HtmlEditor} this
19245 * @event firstfocus
19246 * Fires when on first focus - needed by toolbars..
19247 * @param {HtmlEditor} this
19252 * Auto save the htmlEditor value as a file into Events
19253 * @param {HtmlEditor} this
19257 * @event savedpreview
19258 * preview the saved version of htmlEditor
19259 * @param {HtmlEditor} this
19266 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19270 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19275 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19280 * @cfg {Number} height (in pixels)
19284 * @cfg {Number} width (in pixels)
19289 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19292 stylesheets: false,
19297 // private properties
19298 validationEvent : false,
19300 initialized : false,
19303 onFocus : Roo.emptyFn,
19305 hideMode:'offsets',
19308 tbContainer : false,
19310 toolbarContainer :function() {
19311 return this.wrap.select('.x-html-editor-tb',true).first();
19315 * Protected method that will not generally be called directly. It
19316 * is called when the editor creates its toolbar. Override this method if you need to
19317 * add custom toolbar buttons.
19318 * @param {HtmlEditor} editor
19320 createToolbar : function(){
19322 Roo.log("create toolbars");
19324 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19325 this.toolbars[0].render(this.toolbarContainer());
19329 // if (!editor.toolbars || !editor.toolbars.length) {
19330 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19333 // for (var i =0 ; i < editor.toolbars.length;i++) {
19334 // editor.toolbars[i] = Roo.factory(
19335 // typeof(editor.toolbars[i]) == 'string' ?
19336 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19337 // Roo.bootstrap.HtmlEditor);
19338 // editor.toolbars[i].init(editor);
19344 onRender : function(ct, position)
19346 // Roo.log("Call onRender: " + this.xtype);
19348 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19350 this.wrap = this.inputEl().wrap({
19351 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19354 this.editorcore.onRender(ct, position);
19356 if (this.resizable) {
19357 this.resizeEl = new Roo.Resizable(this.wrap, {
19361 minHeight : this.height,
19362 height: this.height,
19363 handles : this.resizable,
19366 resize : function(r, w, h) {
19367 _t.onResize(w,h); // -something
19373 this.createToolbar(this);
19376 if(!this.width && this.resizable){
19377 this.setSize(this.wrap.getSize());
19379 if (this.resizeEl) {
19380 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19381 // should trigger onReize..
19387 onResize : function(w, h)
19389 Roo.log('resize: ' +w + ',' + h );
19390 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19394 if(this.inputEl() ){
19395 if(typeof w == 'number'){
19396 var aw = w - this.wrap.getFrameWidth('lr');
19397 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19400 if(typeof h == 'number'){
19401 var tbh = -11; // fixme it needs to tool bar size!
19402 for (var i =0; i < this.toolbars.length;i++) {
19403 // fixme - ask toolbars for heights?
19404 tbh += this.toolbars[i].el.getHeight();
19405 //if (this.toolbars[i].footer) {
19406 // tbh += this.toolbars[i].footer.el.getHeight();
19414 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19415 ah -= 5; // knock a few pixes off for look..
19416 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19420 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19421 this.editorcore.onResize(ew,eh);
19426 * Toggles the editor between standard and source edit mode.
19427 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19429 toggleSourceEdit : function(sourceEditMode)
19431 this.editorcore.toggleSourceEdit(sourceEditMode);
19433 if(this.editorcore.sourceEditMode){
19434 Roo.log('editor - showing textarea');
19437 // Roo.log(this.syncValue());
19439 this.inputEl().removeClass(['hide', 'x-hidden']);
19440 this.inputEl().dom.removeAttribute('tabIndex');
19441 this.inputEl().focus();
19443 Roo.log('editor - hiding textarea');
19445 // Roo.log(this.pushValue());
19448 this.inputEl().addClass(['hide', 'x-hidden']);
19449 this.inputEl().dom.setAttribute('tabIndex', -1);
19450 //this.deferFocus();
19453 if(this.resizable){
19454 this.setSize(this.wrap.getSize());
19457 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19460 // private (for BoxComponent)
19461 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19463 // private (for BoxComponent)
19464 getResizeEl : function(){
19468 // private (for BoxComponent)
19469 getPositionEl : function(){
19474 initEvents : function(){
19475 this.originalValue = this.getValue();
19479 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19482 // markInvalid : Roo.emptyFn,
19484 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19487 // clearInvalid : Roo.emptyFn,
19489 setValue : function(v){
19490 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19491 this.editorcore.pushValue();
19496 deferFocus : function(){
19497 this.focus.defer(10, this);
19501 focus : function(){
19502 this.editorcore.focus();
19508 onDestroy : function(){
19514 for (var i =0; i < this.toolbars.length;i++) {
19515 // fixme - ask toolbars for heights?
19516 this.toolbars[i].onDestroy();
19519 this.wrap.dom.innerHTML = '';
19520 this.wrap.remove();
19525 onFirstFocus : function(){
19526 //Roo.log("onFirstFocus");
19527 this.editorcore.onFirstFocus();
19528 for (var i =0; i < this.toolbars.length;i++) {
19529 this.toolbars[i].onFirstFocus();
19535 syncValue : function()
19537 this.editorcore.syncValue();
19540 pushValue : function()
19542 this.editorcore.pushValue();
19546 // hide stuff that is not compatible
19560 * @event specialkey
19564 * @cfg {String} fieldClass @hide
19567 * @cfg {String} focusClass @hide
19570 * @cfg {String} autoCreate @hide
19573 * @cfg {String} inputType @hide
19576 * @cfg {String} invalidClass @hide
19579 * @cfg {String} invalidText @hide
19582 * @cfg {String} msgFx @hide
19585 * @cfg {String} validateOnBlur @hide
19594 Roo.namespace('Roo.bootstrap.htmleditor');
19596 * @class Roo.bootstrap.HtmlEditorToolbar1
19601 new Roo.bootstrap.HtmlEditor({
19604 new Roo.bootstrap.HtmlEditorToolbar1({
19605 disable : { fonts: 1 , format: 1, ..., ... , ...],
19611 * @cfg {Object} disable List of elements to disable..
19612 * @cfg {Array} btns List of additional buttons.
19616 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19619 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19622 Roo.apply(this, config);
19624 // default disabled, based on 'good practice'..
19625 this.disable = this.disable || {};
19626 Roo.applyIf(this.disable, {
19629 specialElements : true
19631 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19633 this.editor = config.editor;
19634 this.editorcore = config.editor.editorcore;
19636 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19638 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19639 // dont call parent... till later.
19641 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
19646 editorcore : false,
19651 "h1","h2","h3","h4","h5","h6",
19653 "abbr", "acronym", "address", "cite", "samp", "var",
19657 onRender : function(ct, position)
19659 // Roo.log("Call onRender: " + this.xtype);
19661 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19663 this.el.dom.style.marginBottom = '0';
19665 var editorcore = this.editorcore;
19666 var editor= this.editor;
19669 var btn = function(id,cmd , toggle, handler){
19671 var event = toggle ? 'toggle' : 'click';
19676 xns: Roo.bootstrap,
19679 enableToggle:toggle !== false,
19681 pressed : toggle ? false : null,
19684 a.listeners[toggle ? 'toggle' : 'click'] = function() {
19685 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
19694 xns: Roo.bootstrap,
19695 glyphicon : 'font',
19699 xns: Roo.bootstrap,
19703 Roo.each(this.formats, function(f) {
19704 style.menu.items.push({
19706 xns: Roo.bootstrap,
19707 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19712 editorcore.insertTag(this.tagname);
19719 children.push(style);
19722 btn('bold',false,true);
19723 btn('italic',false,true);
19724 btn('align-left', 'justifyleft',true);
19725 btn('align-center', 'justifycenter',true);
19726 btn('align-right' , 'justifyright',true);
19727 btn('link', false, false, function(btn) {
19728 //Roo.log("create link?");
19729 var url = prompt(this.createLinkText, this.defaultLinkValue);
19730 if(url && url != 'http:/'+'/'){
19731 this.editorcore.relayCmd('createlink', url);
19734 btn('list','insertunorderedlist',true);
19735 btn('pencil', false,true, function(btn){
19738 this.toggleSourceEdit(btn.pressed);
19744 xns: Roo.bootstrap,
19749 xns: Roo.bootstrap,
19754 cog.menu.items.push({
19756 xns: Roo.bootstrap,
19757 html : Clean styles,
19762 editorcore.insertTag(this.tagname);
19771 this.xtype = 'NavSimplebar';
19773 for(var i=0;i< children.length;i++) {
19775 this.buttons.add(this.addxtypeChild(children[i]));
19779 editor.on('editorevent', this.updateToolbar, this);
19781 onBtnClick : function(id)
19783 this.editorcore.relayCmd(id);
19784 this.editorcore.focus();
19788 * Protected method that will not generally be called directly. It triggers
19789 * a toolbar update by reading the markup state of the current selection in the editor.
19791 updateToolbar: function(){
19793 if(!this.editorcore.activated){
19794 this.editor.onFirstFocus(); // is this neeed?
19798 var btns = this.buttons;
19799 var doc = this.editorcore.doc;
19800 btns.get('bold').setActive(doc.queryCommandState('bold'));
19801 btns.get('italic').setActive(doc.queryCommandState('italic'));
19802 //btns.get('underline').setActive(doc.queryCommandState('underline'));
19804 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19805 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19806 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19808 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19809 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19812 var ans = this.editorcore.getAllAncestors();
19813 if (this.formatCombo) {
19816 var store = this.formatCombo.store;
19817 this.formatCombo.setValue("");
19818 for (var i =0; i < ans.length;i++) {
19819 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19821 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19829 // hides menus... - so this cant be on a menu...
19830 Roo.bootstrap.MenuMgr.hideAll();
19832 Roo.bootstrap.MenuMgr.hideAll();
19833 //this.editorsyncValue();
19835 onFirstFocus: function() {
19836 this.buttons.each(function(item){
19840 toggleSourceEdit : function(sourceEditMode){
19843 if(sourceEditMode){
19844 Roo.log("disabling buttons");
19845 this.buttons.each( function(item){
19846 if(item.cmd != 'pencil'){
19852 Roo.log("enabling buttons");
19853 if(this.editorcore.initialized){
19854 this.buttons.each( function(item){
19860 Roo.log("calling toggole on editor");
19861 // tell the editor that it's been pressed..
19862 this.editor.toggleSourceEdit(sourceEditMode);
19872 * @class Roo.bootstrap.Table.AbstractSelectionModel
19873 * @extends Roo.util.Observable
19874 * Abstract base class for grid SelectionModels. It provides the interface that should be
19875 * implemented by descendant classes. This class should not be directly instantiated.
19878 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19879 this.locked = false;
19880 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19884 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
19885 /** @ignore Called by the grid automatically. Do not call directly. */
19886 init : function(grid){
19892 * Locks the selections.
19895 this.locked = true;
19899 * Unlocks the selections.
19901 unlock : function(){
19902 this.locked = false;
19906 * Returns true if the selections are locked.
19907 * @return {Boolean}
19909 isLocked : function(){
19910 return this.locked;
19914 * @extends Roo.bootstrap.Table.AbstractSelectionModel
19915 * @class Roo.bootstrap.Table.RowSelectionModel
19916 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19917 * It supports multiple selections and keyboard selection/navigation.
19919 * @param {Object} config
19922 Roo.bootstrap.Table.RowSelectionModel = function(config){
19923 Roo.apply(this, config);
19924 this.selections = new Roo.util.MixedCollection(false, function(o){
19929 this.lastActive = false;
19933 * @event selectionchange
19934 * Fires when the selection changes
19935 * @param {SelectionModel} this
19937 "selectionchange" : true,
19939 * @event afterselectionchange
19940 * Fires after the selection changes (eg. by key press or clicking)
19941 * @param {SelectionModel} this
19943 "afterselectionchange" : true,
19945 * @event beforerowselect
19946 * Fires when a row is selected being selected, return false to cancel.
19947 * @param {SelectionModel} this
19948 * @param {Number} rowIndex The selected index
19949 * @param {Boolean} keepExisting False if other selections will be cleared
19951 "beforerowselect" : true,
19954 * Fires when a row is selected.
19955 * @param {SelectionModel} this
19956 * @param {Number} rowIndex The selected index
19957 * @param {Roo.data.Record} r The record
19959 "rowselect" : true,
19961 * @event rowdeselect
19962 * Fires when a row is deselected.
19963 * @param {SelectionModel} this
19964 * @param {Number} rowIndex The selected index
19966 "rowdeselect" : true
19968 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19969 this.locked = false;
19972 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
19974 * @cfg {Boolean} singleSelect
19975 * True to allow selection of only one row at a time (defaults to false)
19977 singleSelect : false,
19980 initEvents : function(){
19982 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19983 this.grid.on("mousedown", this.handleMouseDown, this);
19984 }else{ // allow click to work like normal
19985 this.grid.on("rowclick", this.handleDragableRowClick, this);
19988 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19989 "up" : function(e){
19991 this.selectPrevious(e.shiftKey);
19992 }else if(this.last !== false && this.lastActive !== false){
19993 var last = this.last;
19994 this.selectRange(this.last, this.lastActive-1);
19995 this.grid.getView().focusRow(this.lastActive);
19996 if(last !== false){
20000 this.selectFirstRow();
20002 this.fireEvent("afterselectionchange", this);
20004 "down" : function(e){
20006 this.selectNext(e.shiftKey);
20007 }else if(this.last !== false && this.lastActive !== false){
20008 var last = this.last;
20009 this.selectRange(this.last, this.lastActive+1);
20010 this.grid.getView().focusRow(this.lastActive);
20011 if(last !== false){
20015 this.selectFirstRow();
20017 this.fireEvent("afterselectionchange", this);
20022 var view = this.grid.view;
20023 view.on("refresh", this.onRefresh, this);
20024 view.on("rowupdated", this.onRowUpdated, this);
20025 view.on("rowremoved", this.onRemove, this);
20029 onRefresh : function(){
20030 var ds = this.grid.dataSource, i, v = this.grid.view;
20031 var s = this.selections;
20032 s.each(function(r){
20033 if((i = ds.indexOfId(r.id)) != -1){
20042 onRemove : function(v, index, r){
20043 this.selections.remove(r);
20047 onRowUpdated : function(v, index, r){
20048 if(this.isSelected(r)){
20049 v.onRowSelect(index);
20055 * @param {Array} records The records to select
20056 * @param {Boolean} keepExisting (optional) True to keep existing selections
20058 selectRecords : function(records, keepExisting){
20060 this.clearSelections();
20062 var ds = this.grid.dataSource;
20063 for(var i = 0, len = records.length; i < len; i++){
20064 this.selectRow(ds.indexOf(records[i]), true);
20069 * Gets the number of selected rows.
20072 getCount : function(){
20073 return this.selections.length;
20077 * Selects the first row in the grid.
20079 selectFirstRow : function(){
20084 * Select the last row.
20085 * @param {Boolean} keepExisting (optional) True to keep existing selections
20087 selectLastRow : function(keepExisting){
20088 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20092 * Selects the row immediately following the last selected row.
20093 * @param {Boolean} keepExisting (optional) True to keep existing selections
20095 selectNext : function(keepExisting){
20096 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20097 this.selectRow(this.last+1, keepExisting);
20098 this.grid.getView().focusRow(this.last);
20103 * Selects the row that precedes the last selected row.
20104 * @param {Boolean} keepExisting (optional) True to keep existing selections
20106 selectPrevious : function(keepExisting){
20108 this.selectRow(this.last-1, keepExisting);
20109 this.grid.getView().focusRow(this.last);
20114 * Returns the selected records
20115 * @return {Array} Array of selected records
20117 getSelections : function(){
20118 return [].concat(this.selections.items);
20122 * Returns the first selected record.
20125 getSelected : function(){
20126 return this.selections.itemAt(0);
20131 * Clears all selections.
20133 clearSelections : function(fast){
20134 if(this.locked) return;
20136 var ds = this.grid.dataSource;
20137 var s = this.selections;
20138 s.each(function(r){
20139 this.deselectRow(ds.indexOfId(r.id));
20143 this.selections.clear();
20150 * Selects all rows.
20152 selectAll : function(){
20153 if(this.locked) return;
20154 this.selections.clear();
20155 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20156 this.selectRow(i, true);
20161 * Returns True if there is a selection.
20162 * @return {Boolean}
20164 hasSelection : function(){
20165 return this.selections.length > 0;
20169 * Returns True if the specified row is selected.
20170 * @param {Number/Record} record The record or index of the record to check
20171 * @return {Boolean}
20173 isSelected : function(index){
20174 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20175 return (r && this.selections.key(r.id) ? true : false);
20179 * Returns True if the specified record id is selected.
20180 * @param {String} id The id of record to check
20181 * @return {Boolean}
20183 isIdSelected : function(id){
20184 return (this.selections.key(id) ? true : false);
20188 handleMouseDown : function(e, t){
20189 var view = this.grid.getView(), rowIndex;
20190 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20193 if(e.shiftKey && this.last !== false){
20194 var last = this.last;
20195 this.selectRange(last, rowIndex, e.ctrlKey);
20196 this.last = last; // reset the last
20197 view.focusRow(rowIndex);
20199 var isSelected = this.isSelected(rowIndex);
20200 if(e.button !== 0 && isSelected){
20201 view.focusRow(rowIndex);
20202 }else if(e.ctrlKey && isSelected){
20203 this.deselectRow(rowIndex);
20204 }else if(!isSelected){
20205 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20206 view.focusRow(rowIndex);
20209 this.fireEvent("afterselectionchange", this);
20212 handleDragableRowClick : function(grid, rowIndex, e)
20214 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20215 this.selectRow(rowIndex, false);
20216 grid.view.focusRow(rowIndex);
20217 this.fireEvent("afterselectionchange", this);
20222 * Selects multiple rows.
20223 * @param {Array} rows Array of the indexes of the row to select
20224 * @param {Boolean} keepExisting (optional) True to keep existing selections
20226 selectRows : function(rows, keepExisting){
20228 this.clearSelections();
20230 for(var i = 0, len = rows.length; i < len; i++){
20231 this.selectRow(rows[i], true);
20236 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20237 * @param {Number} startRow The index of the first row in the range
20238 * @param {Number} endRow The index of the last row in the range
20239 * @param {Boolean} keepExisting (optional) True to retain existing selections
20241 selectRange : function(startRow, endRow, keepExisting){
20242 if(this.locked) return;
20244 this.clearSelections();
20246 if(startRow <= endRow){
20247 for(var i = startRow; i <= endRow; i++){
20248 this.selectRow(i, true);
20251 for(var i = startRow; i >= endRow; i--){
20252 this.selectRow(i, true);
20258 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20259 * @param {Number} startRow The index of the first row in the range
20260 * @param {Number} endRow The index of the last row in the range
20262 deselectRange : function(startRow, endRow, preventViewNotify){
20263 if(this.locked) return;
20264 for(var i = startRow; i <= endRow; i++){
20265 this.deselectRow(i, preventViewNotify);
20271 * @param {Number} row The index of the row to select
20272 * @param {Boolean} keepExisting (optional) True to keep existing selections
20274 selectRow : function(index, keepExisting, preventViewNotify){
20275 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20276 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20277 if(!keepExisting || this.singleSelect){
20278 this.clearSelections();
20280 var r = this.grid.dataSource.getAt(index);
20281 this.selections.add(r);
20282 this.last = this.lastActive = index;
20283 if(!preventViewNotify){
20284 this.grid.getView().onRowSelect(index);
20286 this.fireEvent("rowselect", this, index, r);
20287 this.fireEvent("selectionchange", this);
20293 * @param {Number} row The index of the row to deselect
20295 deselectRow : function(index, preventViewNotify){
20296 if(this.locked) return;
20297 if(this.last == index){
20300 if(this.lastActive == index){
20301 this.lastActive = false;
20303 var r = this.grid.dataSource.getAt(index);
20304 this.selections.remove(r);
20305 if(!preventViewNotify){
20306 this.grid.getView().onRowDeselect(index);
20308 this.fireEvent("rowdeselect", this, index);
20309 this.fireEvent("selectionchange", this);
20313 restoreLast : function(){
20315 this.last = this._last;
20320 acceptsNav : function(row, col, cm){
20321 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20325 onEditorKey : function(field, e){
20326 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20331 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20333 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20335 }else if(k == e.ENTER && !e.ctrlKey){
20339 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20341 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20343 }else if(k == e.ESC){
20347 g.startEditing(newCell[0], newCell[1]);
20352 * Ext JS Library 1.1.1
20353 * Copyright(c) 2006-2007, Ext JS, LLC.
20355 * Originally Released Under LGPL - original licence link has changed is not relivant.
20358 * <script type="text/javascript">
20362 * @class Roo.bootstrap.PagingToolbar
20364 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20366 * Create a new PagingToolbar
20367 * @param {Object} config The config object
20369 Roo.bootstrap.PagingToolbar = function(config)
20371 // old args format still supported... - xtype is prefered..
20372 // created from xtype...
20373 var ds = config.dataSource;
20374 this.toolbarItems = [];
20375 if (config.items) {
20376 this.toolbarItems = config.items;
20377 // config.items = [];
20380 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20387 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20391 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20393 * @cfg {Roo.data.Store} dataSource
20394 * The underlying data store providing the paged data
20397 * @cfg {String/HTMLElement/Element} container
20398 * container The id or element that will contain the toolbar
20401 * @cfg {Boolean} displayInfo
20402 * True to display the displayMsg (defaults to false)
20405 * @cfg {Number} pageSize
20406 * The number of records to display per page (defaults to 20)
20410 * @cfg {String} displayMsg
20411 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20413 displayMsg : 'Displaying {0} - {1} of {2}',
20415 * @cfg {String} emptyMsg
20416 * The message to display when no records are found (defaults to "No data to display")
20418 emptyMsg : 'No data to display',
20420 * Customizable piece of the default paging text (defaults to "Page")
20423 beforePageText : "Page",
20425 * Customizable piece of the default paging text (defaults to "of %0")
20428 afterPageText : "of {0}",
20430 * Customizable piece of the default paging text (defaults to "First Page")
20433 firstText : "First Page",
20435 * Customizable piece of the default paging text (defaults to "Previous Page")
20438 prevText : "Previous Page",
20440 * Customizable piece of the default paging text (defaults to "Next Page")
20443 nextText : "Next Page",
20445 * Customizable piece of the default paging text (defaults to "Last Page")
20448 lastText : "Last Page",
20450 * Customizable piece of the default paging text (defaults to "Refresh")
20453 refreshText : "Refresh",
20457 onRender : function(ct, position)
20459 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20460 this.navgroup.parentId = this.id;
20461 this.navgroup.onRender(this.el, null);
20462 // add the buttons to the navgroup
20464 if(this.displayInfo){
20465 Roo.log(this.el.select('ul.navbar-nav',true).first());
20466 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20467 this.displayEl = this.el.select('.x-paging-info', true).first();
20468 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20469 // this.displayEl = navel.el.select('span',true).first();
20475 Roo.each(_this.buttons, function(e){
20476 Roo.factory(e).onRender(_this.el, null);
20480 Roo.each(_this.toolbarItems, function(e) {
20481 _this.navgroup.addItem(e);
20485 this.first = this.navgroup.addItem({
20486 tooltip: this.firstText,
20488 icon : 'fa fa-backward',
20490 preventDefault: true,
20491 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20494 this.prev = this.navgroup.addItem({
20495 tooltip: this.prevText,
20497 icon : 'fa fa-step-backward',
20499 preventDefault: true,
20500 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20502 //this.addSeparator();
20505 var field = this.navgroup.addItem( {
20507 cls : 'x-paging-position',
20509 html : this.beforePageText +
20510 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20511 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20514 this.field = field.el.select('input', true).first();
20515 this.field.on("keydown", this.onPagingKeydown, this);
20516 this.field.on("focus", function(){this.dom.select();});
20519 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20520 //this.field.setHeight(18);
20521 //this.addSeparator();
20522 this.next = this.navgroup.addItem({
20523 tooltip: this.nextText,
20525 html : ' <i class="fa fa-step-forward">',
20527 preventDefault: true,
20528 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20530 this.last = this.navgroup.addItem({
20531 tooltip: this.lastText,
20532 icon : 'fa fa-forward',
20535 preventDefault: true,
20536 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20538 //this.addSeparator();
20539 this.loading = this.navgroup.addItem({
20540 tooltip: this.refreshText,
20541 icon: 'fa fa-refresh',
20542 preventDefault: true,
20543 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20549 updateInfo : function(){
20550 if(this.displayEl){
20551 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20552 var msg = count == 0 ?
20556 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20558 this.displayEl.update(msg);
20563 onLoad : function(ds, r, o){
20564 this.cursor = o.params ? o.params.start : 0;
20565 var d = this.getPageData(),
20569 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20570 this.field.dom.value = ap;
20571 this.first.setDisabled(ap == 1);
20572 this.prev.setDisabled(ap == 1);
20573 this.next.setDisabled(ap == ps);
20574 this.last.setDisabled(ap == ps);
20575 this.loading.enable();
20580 getPageData : function(){
20581 var total = this.ds.getTotalCount();
20584 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20585 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20590 onLoadError : function(){
20591 this.loading.enable();
20595 onPagingKeydown : function(e){
20596 var k = e.getKey();
20597 var d = this.getPageData();
20599 var v = this.field.dom.value, pageNum;
20600 if(!v || isNaN(pageNum = parseInt(v, 10))){
20601 this.field.dom.value = d.activePage;
20604 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20605 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20608 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))
20610 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20611 this.field.dom.value = pageNum;
20612 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20615 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20617 var v = this.field.dom.value, pageNum;
20618 var increment = (e.shiftKey) ? 10 : 1;
20619 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20621 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20622 this.field.dom.value = d.activePage;
20625 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20627 this.field.dom.value = parseInt(v, 10) + increment;
20628 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20629 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20636 beforeLoad : function(){
20638 this.loading.disable();
20643 onClick : function(which){
20652 ds.load({params:{start: 0, limit: this.pageSize}});
20655 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20658 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20661 var total = ds.getTotalCount();
20662 var extra = total % this.pageSize;
20663 var lastStart = extra ? (total - extra) : total-this.pageSize;
20664 ds.load({params:{start: lastStart, limit: this.pageSize}});
20667 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20673 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20674 * @param {Roo.data.Store} store The data store to unbind
20676 unbind : function(ds){
20677 ds.un("beforeload", this.beforeLoad, this);
20678 ds.un("load", this.onLoad, this);
20679 ds.un("loadexception", this.onLoadError, this);
20680 ds.un("remove", this.updateInfo, this);
20681 ds.un("add", this.updateInfo, this);
20682 this.ds = undefined;
20686 * Binds the paging toolbar to the specified {@link Roo.data.Store}
20687 * @param {Roo.data.Store} store The data store to bind
20689 bind : function(ds){
20690 ds.on("beforeload", this.beforeLoad, this);
20691 ds.on("load", this.onLoad, this);
20692 ds.on("loadexception", this.onLoadError, this);
20693 ds.on("remove", this.updateInfo, this);
20694 ds.on("add", this.updateInfo, this);
20705 * @class Roo.bootstrap.MessageBar
20706 * @extends Roo.bootstrap.Component
20707 * Bootstrap MessageBar class
20708 * @cfg {String} html contents of the MessageBar
20709 * @cfg {String} weight (info | success | warning | danger) default info
20710 * @cfg {String} beforeClass insert the bar before the given class
20711 * @cfg {Boolean} closable (true | false) default false
20712 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20715 * Create a new Element
20716 * @param {Object} config The config object
20719 Roo.bootstrap.MessageBar = function(config){
20720 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20723 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
20729 beforeClass: 'bootstrap-sticky-wrap',
20731 getAutoCreate : function(){
20735 cls: 'alert alert-dismissable alert-' + this.weight,
20740 html: this.html || ''
20746 cfg.cls += ' alert-messages-fixed';
20760 onRender : function(ct, position)
20762 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20765 var cfg = Roo.apply({}, this.getAutoCreate());
20769 cfg.cls += ' ' + this.cls;
20772 cfg.style = this.style;
20774 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20776 this.el.setVisibilityMode(Roo.Element.DISPLAY);
20779 this.el.select('>button.close').on('click', this.hide, this);
20785 if (!this.rendered) {
20791 this.fireEvent('show', this);
20797 if (!this.rendered) {
20803 this.fireEvent('hide', this);
20806 update : function()
20808 // var e = this.el.dom.firstChild;
20810 // if(this.closable){
20811 // e = e.nextSibling;
20814 // e.data = this.html || '';
20816 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20832 * @class Roo.bootstrap.Graph
20833 * @extends Roo.bootstrap.Component
20834 * Bootstrap Graph class
20838 @cfg {String} graphtype bar | vbar | pie
20839 @cfg {number} g_x coodinator | centre x (pie)
20840 @cfg {number} g_y coodinator | centre y (pie)
20841 @cfg {number} g_r radius (pie)
20842 @cfg {number} g_height height of the chart (respected by all elements in the set)
20843 @cfg {number} g_width width of the chart (respected by all elements in the set)
20844 @cfg {Object} title The title of the chart
20847 -opts (object) options for the chart
20849 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20850 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20852 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.
20853 o stacked (boolean) whether or not to tread values as in a stacked bar chart
20855 o stretch (boolean)
20857 -opts (object) options for the pie
20860 o startAngle (number)
20861 o endAngle (number)
20865 * Create a new Input
20866 * @param {Object} config The config object
20869 Roo.bootstrap.Graph = function(config){
20870 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20876 * The img click event for the img.
20877 * @param {Roo.EventObject} e
20883 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
20894 //g_colors: this.colors,
20901 getAutoCreate : function(){
20912 onRender : function(ct,position){
20913 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20914 this.raphael = Raphael(this.el.dom);
20916 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20917 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20918 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20919 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20921 r.text(160, 10, "Single Series Chart").attr(txtattr);
20922 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20923 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20924 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20926 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20927 r.barchart(330, 10, 300, 220, data1);
20928 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20929 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20932 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20933 // r.barchart(30, 30, 560, 250, xdata, {
20934 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20935 // axis : "0 0 1 1",
20936 // axisxlabels : xdata
20937 // //yvalues : cols,
20940 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20942 // this.load(null,xdata,{
20943 // axis : "0 0 1 1",
20944 // axisxlabels : xdata
20949 load : function(graphtype,xdata,opts){
20950 this.raphael.clear();
20952 graphtype = this.graphtype;
20957 var r = this.raphael,
20958 fin = function () {
20959 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20961 fout = function () {
20962 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20964 pfin = function() {
20965 this.sector.stop();
20966 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20969 this.label[0].stop();
20970 this.label[0].attr({ r: 7.5 });
20971 this.label[1].attr({ "font-weight": 800 });
20974 pfout = function() {
20975 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20978 this.label[0].animate({ r: 5 }, 500, "bounce");
20979 this.label[1].attr({ "font-weight": 400 });
20985 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20988 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20991 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
20992 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20994 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21001 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21006 setTitle: function(o)
21011 initEvents: function() {
21014 this.el.on('click', this.onClick, this);
21018 onClick : function(e)
21020 Roo.log('img onclick');
21021 this.fireEvent('click', this, e);
21033 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21036 * @class Roo.bootstrap.dash.NumberBox
21037 * @extends Roo.bootstrap.Component
21038 * Bootstrap NumberBox class
21039 * @cfg {String} headline Box headline
21040 * @cfg {String} content Box content
21041 * @cfg {String} icon Box icon
21042 * @cfg {String} footer Footer text
21043 * @cfg {String} fhref Footer href
21046 * Create a new NumberBox
21047 * @param {Object} config The config object
21051 Roo.bootstrap.dash.NumberBox = function(config){
21052 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21056 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21065 getAutoCreate : function(){
21069 cls : 'small-box ',
21077 cls : 'roo-headline',
21078 html : this.headline
21082 cls : 'roo-content',
21083 html : this.content
21097 cls : 'ion ' + this.icon
21106 cls : 'small-box-footer',
21107 href : this.fhref || '#',
21111 cfg.cn.push(footer);
21118 onRender : function(ct,position){
21119 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21126 setHeadline: function (value)
21128 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21131 setFooter: function (value, href)
21133 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21136 this.el.select('a.small-box-footer',true).first().attr('href', href);
21141 setContent: function (value)
21143 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21146 initEvents: function()
21160 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21163 * @class Roo.bootstrap.dash.TabBox
21164 * @extends Roo.bootstrap.Component
21165 * Bootstrap TabBox class
21166 * @cfg {String} title Title of the TabBox
21167 * @cfg {String} icon Icon of the TabBox
21168 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21169 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21172 * Create a new TabBox
21173 * @param {Object} config The config object
21177 Roo.bootstrap.dash.TabBox = function(config){
21178 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21183 * When a pane is added
21184 * @param {Roo.bootstrap.dash.TabPane} pane
21188 * @event activatepane
21189 * When a pane is activated
21190 * @param {Roo.bootstrap.dash.TabPane} pane
21192 "activatepane" : true
21200 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21205 tabScrollable : false,
21207 getChildContainer : function()
21209 return this.el.select('.tab-content', true).first();
21212 getAutoCreate : function(){
21216 cls: 'pull-left header',
21224 cls: 'fa ' + this.icon
21230 cls: 'nav nav-tabs pull-right',
21236 if(this.tabScrollable){
21243 cls: 'nav nav-tabs pull-right',
21254 cls: 'nav-tabs-custom',
21259 cls: 'tab-content no-padding',
21267 initEvents : function()
21269 //Roo.log('add add pane handler');
21270 this.on('addpane', this.onAddPane, this);
21273 * Updates the box title
21274 * @param {String} html to set the title to.
21276 setTitle : function(value)
21278 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21280 onAddPane : function(pane)
21282 this.panes.push(pane);
21283 //Roo.log('addpane');
21285 // tabs are rendere left to right..
21286 if(!this.showtabs){
21290 var ctr = this.el.select('.nav-tabs', true).first();
21293 var existing = ctr.select('.nav-tab',true);
21294 var qty = existing.getCount();;
21297 var tab = ctr.createChild({
21299 cls : 'nav-tab' + (qty ? '' : ' active'),
21307 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21310 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21312 pane.el.addClass('active');
21317 onTabClick : function(ev,un,ob,pane)
21319 //Roo.log('tab - prev default');
21320 ev.preventDefault();
21323 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21324 pane.tab.addClass('active');
21325 //Roo.log(pane.title);
21326 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21327 // technically we should have a deactivate event.. but maybe add later.
21328 // and it should not de-activate the selected tab...
21329 this.fireEvent('activatepane', pane);
21330 pane.el.addClass('active');
21331 pane.fireEvent('activate');
21336 getActivePane : function()
21339 Roo.each(this.panes, function(p) {
21340 if(p.el.hasClass('active')){
21361 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21363 * @class Roo.bootstrap.TabPane
21364 * @extends Roo.bootstrap.Component
21365 * Bootstrap TabPane class
21366 * @cfg {Boolean} active (false | true) Default false
21367 * @cfg {String} title title of panel
21371 * Create a new TabPane
21372 * @param {Object} config The config object
21375 Roo.bootstrap.dash.TabPane = function(config){
21376 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21382 * When a pane is activated
21383 * @param {Roo.bootstrap.dash.TabPane} pane
21390 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21395 // the tabBox that this is attached to.
21398 getAutoCreate : function()
21406 cfg.cls += ' active';
21411 initEvents : function()
21413 //Roo.log('trigger add pane handler');
21414 this.parent().fireEvent('addpane', this)
21418 * Updates the tab title
21419 * @param {String} html to set the title to.
21421 setTitle: function(str)
21427 this.tab.select('a', true).first().dom.innerHTML = str;
21444 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21447 * @class Roo.bootstrap.menu.Menu
21448 * @extends Roo.bootstrap.Component
21449 * Bootstrap Menu class - container for Menu
21450 * @cfg {String} html Text of the menu
21451 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21452 * @cfg {String} icon Font awesome icon
21453 * @cfg {String} pos Menu align to (top | bottom) default bottom
21457 * Create a new Menu
21458 * @param {Object} config The config object
21462 Roo.bootstrap.menu.Menu = function(config){
21463 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21467 * @event beforeshow
21468 * Fires before this menu is displayed
21469 * @param {Roo.bootstrap.menu.Menu} this
21473 * @event beforehide
21474 * Fires before this menu is hidden
21475 * @param {Roo.bootstrap.menu.Menu} this
21480 * Fires after this menu is displayed
21481 * @param {Roo.bootstrap.menu.Menu} this
21486 * Fires after this menu is hidden
21487 * @param {Roo.bootstrap.menu.Menu} this
21492 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21493 * @param {Roo.bootstrap.menu.Menu} this
21494 * @param {Roo.EventObject} e
21501 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21505 weight : 'default',
21510 getChildContainer : function() {
21511 if(this.isSubMenu){
21515 return this.el.select('ul.dropdown-menu', true).first();
21518 getAutoCreate : function()
21523 cls : 'roo-menu-text',
21531 cls : 'fa ' + this.icon
21542 cls : 'dropdown-button btn btn-' + this.weight,
21547 cls : 'dropdown-toggle btn btn-' + this.weight,
21557 cls : 'dropdown-menu'
21563 if(this.pos == 'top'){
21564 cfg.cls += ' dropup';
21567 if(this.isSubMenu){
21570 cls : 'dropdown-menu'
21577 onRender : function(ct, position)
21579 this.isSubMenu = ct.hasClass('dropdown-submenu');
21581 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21584 initEvents : function()
21586 if(this.isSubMenu){
21590 this.hidden = true;
21592 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21593 this.triggerEl.on('click', this.onTriggerPress, this);
21595 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21596 this.buttonEl.on('click', this.onClick, this);
21602 if(this.isSubMenu){
21606 return this.el.select('ul.dropdown-menu', true).first();
21609 onClick : function(e)
21611 this.fireEvent("click", this, e);
21614 onTriggerPress : function(e)
21616 if (this.isVisible()) {
21623 isVisible : function(){
21624 return !this.hidden;
21629 this.fireEvent("beforeshow", this);
21631 this.hidden = false;
21632 this.el.addClass('open');
21634 Roo.get(document).on("mouseup", this.onMouseUp, this);
21636 this.fireEvent("show", this);
21643 this.fireEvent("beforehide", this);
21645 this.hidden = true;
21646 this.el.removeClass('open');
21648 Roo.get(document).un("mouseup", this.onMouseUp);
21650 this.fireEvent("hide", this);
21653 onMouseUp : function()
21667 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21670 * @class Roo.bootstrap.menu.Item
21671 * @extends Roo.bootstrap.Component
21672 * Bootstrap MenuItem class
21673 * @cfg {Boolean} submenu (true | false) default false
21674 * @cfg {String} html text of the item
21675 * @cfg {String} href the link
21676 * @cfg {Boolean} disable (true | false) default false
21677 * @cfg {Boolean} preventDefault (true | false) default true
21678 * @cfg {String} icon Font awesome icon
21679 * @cfg {String} pos Submenu align to (left | right) default right
21683 * Create a new Item
21684 * @param {Object} config The config object
21688 Roo.bootstrap.menu.Item = function(config){
21689 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21693 * Fires when the mouse is hovering over this menu
21694 * @param {Roo.bootstrap.menu.Item} this
21695 * @param {Roo.EventObject} e
21700 * Fires when the mouse exits this menu
21701 * @param {Roo.bootstrap.menu.Item} this
21702 * @param {Roo.EventObject} e
21708 * The raw click event for the entire grid.
21709 * @param {Roo.EventObject} e
21715 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
21720 preventDefault: true,
21725 getAutoCreate : function()
21730 cls : 'roo-menu-item-text',
21738 cls : 'fa ' + this.icon
21747 href : this.href || '#',
21754 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21758 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21760 if(this.pos == 'left'){
21761 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21768 initEvents : function()
21770 this.el.on('mouseover', this.onMouseOver, this);
21771 this.el.on('mouseout', this.onMouseOut, this);
21773 this.el.select('a', true).first().on('click', this.onClick, this);
21777 onClick : function(e)
21779 if(this.preventDefault){
21780 e.preventDefault();
21783 this.fireEvent("click", this, e);
21786 onMouseOver : function(e)
21788 if(this.submenu && this.pos == 'left'){
21789 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21792 this.fireEvent("mouseover", this, e);
21795 onMouseOut : function(e)
21797 this.fireEvent("mouseout", this, e);
21809 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21812 * @class Roo.bootstrap.menu.Separator
21813 * @extends Roo.bootstrap.Component
21814 * Bootstrap Separator class
21817 * Create a new Separator
21818 * @param {Object} config The config object
21822 Roo.bootstrap.menu.Separator = function(config){
21823 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21826 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
21828 getAutoCreate : function(){
21849 * @class Roo.bootstrap.Tooltip
21850 * Bootstrap Tooltip class
21851 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21852 * to determine which dom element triggers the tooltip.
21854 * It needs to add support for additional attributes like tooltip-position
21857 * Create a new Toolti
21858 * @param {Object} config The config object
21861 Roo.bootstrap.Tooltip = function(config){
21862 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21865 Roo.apply(Roo.bootstrap.Tooltip, {
21867 * @function init initialize tooltip monitoring.
21871 currentTip : false,
21872 currentRegion : false,
21878 Roo.get(document).on('mouseover', this.enter ,this);
21879 Roo.get(document).on('mouseout', this.leave, this);
21882 this.currentTip = new Roo.bootstrap.Tooltip();
21885 enter : function(ev)
21887 var dom = ev.getTarget();
21889 //Roo.log(['enter',dom]);
21890 var el = Roo.fly(dom);
21891 if (this.currentEl) {
21893 //Roo.log(this.currentEl);
21894 //Roo.log(this.currentEl.contains(dom));
21895 if (this.currentEl == el) {
21898 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21906 if (this.currentTip.el) {
21907 this.currentTip.el.hide(); // force hiding...
21912 // you can not look for children, as if el is the body.. then everythign is the child..
21913 if (!el.attr('tooltip')) { //
21914 if (!el.select("[tooltip]").elements.length) {
21917 // is the mouse over this child...?
21918 bindEl = el.select("[tooltip]").first();
21919 var xy = ev.getXY();
21920 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21921 //Roo.log("not in region.");
21924 //Roo.log("child element over..");
21927 this.currentEl = bindEl;
21928 this.currentTip.bind(bindEl);
21929 this.currentRegion = Roo.lib.Region.getRegion(dom);
21930 this.currentTip.enter();
21933 leave : function(ev)
21935 var dom = ev.getTarget();
21936 //Roo.log(['leave',dom]);
21937 if (!this.currentEl) {
21942 if (dom != this.currentEl.dom) {
21945 var xy = ev.getXY();
21946 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
21949 // only activate leave if mouse cursor is outside... bounding box..
21954 if (this.currentTip) {
21955 this.currentTip.leave();
21957 //Roo.log('clear currentEl');
21958 this.currentEl = false;
21963 'left' : ['r-l', [-2,0], 'right'],
21964 'right' : ['l-r', [2,0], 'left'],
21965 'bottom' : ['t-b', [0,2], 'top'],
21966 'top' : [ 'b-t', [0,-2], 'bottom']
21972 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
21977 delay : null, // can be { show : 300 , hide: 500}
21981 hoverState : null, //???
21983 placement : 'bottom',
21985 getAutoCreate : function(){
21992 cls : 'tooltip-arrow'
21995 cls : 'tooltip-inner'
22002 bind : function(el)
22008 enter : function () {
22010 if (this.timeout != null) {
22011 clearTimeout(this.timeout);
22014 this.hoverState = 'in';
22015 //Roo.log("enter - show");
22016 if (!this.delay || !this.delay.show) {
22021 this.timeout = setTimeout(function () {
22022 if (_t.hoverState == 'in') {
22025 }, this.delay.show);
22029 clearTimeout(this.timeout);
22031 this.hoverState = 'out';
22032 if (!this.delay || !this.delay.hide) {
22038 this.timeout = setTimeout(function () {
22039 //Roo.log("leave - timeout");
22041 if (_t.hoverState == 'out') {
22043 Roo.bootstrap.Tooltip.currentEl = false;
22051 this.render(document.body);
22054 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22056 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22058 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22060 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22062 var placement = typeof this.placement == 'function' ?
22063 this.placement.call(this, this.el, on_el) :
22066 var autoToken = /\s?auto?\s?/i;
22067 var autoPlace = autoToken.test(placement);
22069 placement = placement.replace(autoToken, '') || 'top';
22073 //this.el.setXY([0,0]);
22075 //this.el.dom.style.display='block';
22076 this.el.addClass(placement);
22078 //this.el.appendTo(on_el);
22080 var p = this.getPosition();
22081 var box = this.el.getBox();
22086 var align = Roo.bootstrap.Tooltip.alignment[placement];
22087 this.el.alignTo(this.bindEl, align[0],align[1]);
22088 //var arrow = this.el.select('.arrow',true).first();
22089 //arrow.set(align[2],
22091 this.el.addClass('in fade');
22092 this.hoverState = null;
22094 if (this.el.hasClass('fade')) {
22105 //this.el.setXY([0,0]);
22106 this.el.removeClass('in');
22122 * @class Roo.bootstrap.LocationPicker
22123 * @extends Roo.bootstrap.Component
22124 * Bootstrap LocationPicker class
22125 * @cfg {Number} latitude Position when init default 0
22126 * @cfg {Number} longitude Position when init default 0
22127 * @cfg {Number} zoom default 15
22128 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22129 * @cfg {Boolean} mapTypeControl default false
22130 * @cfg {Boolean} disableDoubleClickZoom default false
22131 * @cfg {Boolean} scrollwheel default true
22132 * @cfg {Boolean} streetViewControl default false
22133 * @cfg {Number} radius default 0
22134 * @cfg {String} locationName
22135 * @cfg {Boolean} draggable default true
22136 * @cfg {Boolean} enableAutocomplete default false
22137 * @cfg {Boolean} enableReverseGeocode default true
22138 * @cfg {String} markerTitle
22141 * Create a new LocationPicker
22142 * @param {Object} config The config object
22146 Roo.bootstrap.LocationPicker = function(config){
22148 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22153 * Fires when the picker initialized.
22154 * @param {Roo.bootstrap.LocationPicker} this
22155 * @param {Google Location} location
22159 * @event positionchanged
22160 * Fires when the picker position changed.
22161 * @param {Roo.bootstrap.LocationPicker} this
22162 * @param {Google Location} location
22164 positionchanged : true,
22167 * Fires when the map resize.
22168 * @param {Roo.bootstrap.LocationPicker} this
22173 * Fires when the map show.
22174 * @param {Roo.bootstrap.LocationPicker} this
22179 * Fires when the map hide.
22180 * @param {Roo.bootstrap.LocationPicker} this
22185 * Fires when click the map.
22186 * @param {Roo.bootstrap.LocationPicker} this
22187 * @param {Map event} e
22191 * @event mapRightClick
22192 * Fires when right click the map.
22193 * @param {Roo.bootstrap.LocationPicker} this
22194 * @param {Map event} e
22196 mapRightClick : true,
22198 * @event markerClick
22199 * Fires when click the marker.
22200 * @param {Roo.bootstrap.LocationPicker} this
22201 * @param {Map event} e
22203 markerClick : true,
22205 * @event markerRightClick
22206 * Fires when right click the marker.
22207 * @param {Roo.bootstrap.LocationPicker} this
22208 * @param {Map event} e
22210 markerRightClick : true,
22212 * @event OverlayViewDraw
22213 * Fires when OverlayView Draw
22214 * @param {Roo.bootstrap.LocationPicker} this
22216 OverlayViewDraw : true,
22218 * @event OverlayViewOnAdd
22219 * Fires when OverlayView Draw
22220 * @param {Roo.bootstrap.LocationPicker} this
22222 OverlayViewOnAdd : true,
22224 * @event OverlayViewOnRemove
22225 * Fires when OverlayView Draw
22226 * @param {Roo.bootstrap.LocationPicker} this
22228 OverlayViewOnRemove : true,
22230 * @event OverlayViewShow
22231 * Fires when OverlayView Draw
22232 * @param {Roo.bootstrap.LocationPicker} this
22233 * @param {Pixel} cpx
22235 OverlayViewShow : true,
22237 * @event OverlayViewHide
22238 * Fires when OverlayView Draw
22239 * @param {Roo.bootstrap.LocationPicker} this
22241 OverlayViewHide : true
22246 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22248 gMapContext: false,
22254 mapTypeControl: false,
22255 disableDoubleClickZoom: false,
22257 streetViewControl: false,
22261 enableAutocomplete: false,
22262 enableReverseGeocode: true,
22265 getAutoCreate: function()
22270 cls: 'roo-location-picker'
22276 initEvents: function(ct, position)
22278 if(!this.el.getWidth() || this.isApplied()){
22282 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22287 initial: function()
22289 if(!this.mapTypeId){
22290 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22293 this.gMapContext = this.GMapContext();
22295 this.initOverlayView();
22297 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22301 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22302 _this.setPosition(_this.gMapContext.marker.position);
22305 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22306 _this.fireEvent('mapClick', this, event);
22310 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22311 _this.fireEvent('mapRightClick', this, event);
22315 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22316 _this.fireEvent('markerClick', this, event);
22320 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22321 _this.fireEvent('markerRightClick', this, event);
22325 this.setPosition(this.gMapContext.location);
22327 this.fireEvent('initial', this, this.gMapContext.location);
22330 initOverlayView: function()
22334 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22338 _this.fireEvent('OverlayViewDraw', _this);
22343 _this.fireEvent('OverlayViewOnAdd', _this);
22346 onRemove: function()
22348 _this.fireEvent('OverlayViewOnRemove', _this);
22351 show: function(cpx)
22353 _this.fireEvent('OverlayViewShow', _this, cpx);
22358 _this.fireEvent('OverlayViewHide', _this);
22364 fromLatLngToContainerPixel: function(event)
22366 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22369 isApplied: function()
22371 return this.getGmapContext() == false ? false : true;
22374 getGmapContext: function()
22376 return this.gMapContext
22379 GMapContext: function()
22381 var position = new google.maps.LatLng(this.latitude, this.longitude);
22383 var _map = new google.maps.Map(this.el.dom, {
22386 mapTypeId: this.mapTypeId,
22387 mapTypeControl: this.mapTypeControl,
22388 disableDoubleClickZoom: this.disableDoubleClickZoom,
22389 scrollwheel: this.scrollwheel,
22390 streetViewControl: this.streetViewControl,
22391 locationName: this.locationName,
22392 draggable: this.draggable,
22393 enableAutocomplete: this.enableAutocomplete,
22394 enableReverseGeocode: this.enableReverseGeocode
22397 var _marker = new google.maps.Marker({
22398 position: position,
22400 title: this.markerTitle,
22401 draggable: this.draggable
22408 location: position,
22409 radius: this.radius,
22410 locationName: this.locationName,
22411 addressComponents: {
22412 formatted_address: null,
22413 addressLine1: null,
22414 addressLine2: null,
22416 streetNumber: null,
22420 stateOrProvince: null
22423 domContainer: this.el.dom,
22424 geodecoder: new google.maps.Geocoder()
22428 drawCircle: function(center, radius, options)
22430 if (this.gMapContext.circle != null) {
22431 this.gMapContext.circle.setMap(null);
22435 options = Roo.apply({}, options, {
22436 strokeColor: "#0000FF",
22437 strokeOpacity: .35,
22439 fillColor: "#0000FF",
22443 options.map = this.gMapContext.map;
22444 options.radius = radius;
22445 options.center = center;
22446 this.gMapContext.circle = new google.maps.Circle(options);
22447 return this.gMapContext.circle;
22453 setPosition: function(location)
22455 this.gMapContext.location = location;
22456 this.gMapContext.marker.setPosition(location);
22457 this.gMapContext.map.panTo(location);
22458 this.drawCircle(location, this.gMapContext.radius, {});
22462 if (this.gMapContext.settings.enableReverseGeocode) {
22463 this.gMapContext.geodecoder.geocode({
22464 latLng: this.gMapContext.location
22465 }, function(results, status) {
22467 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22468 _this.gMapContext.locationName = results[0].formatted_address;
22469 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22471 _this.fireEvent('positionchanged', this, location);
22478 this.fireEvent('positionchanged', this, location);
22483 google.maps.event.trigger(this.gMapContext.map, "resize");
22485 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22487 this.fireEvent('resize', this);
22490 setPositionByLatLng: function(latitude, longitude)
22492 this.setPosition(new google.maps.LatLng(latitude, longitude));
22495 getCurrentPosition: function()
22498 latitude: this.gMapContext.location.lat(),
22499 longitude: this.gMapContext.location.lng()
22503 getAddressName: function()
22505 return this.gMapContext.locationName;
22508 getAddressComponents: function()
22510 return this.gMapContext.addressComponents;
22513 address_component_from_google_geocode: function(address_components)
22517 for (var i = 0; i < address_components.length; i++) {
22518 var component = address_components[i];
22519 if (component.types.indexOf("postal_code") >= 0) {
22520 result.postalCode = component.short_name;
22521 } else if (component.types.indexOf("street_number") >= 0) {
22522 result.streetNumber = component.short_name;
22523 } else if (component.types.indexOf("route") >= 0) {
22524 result.streetName = component.short_name;
22525 } else if (component.types.indexOf("neighborhood") >= 0) {
22526 result.city = component.short_name;
22527 } else if (component.types.indexOf("locality") >= 0) {
22528 result.city = component.short_name;
22529 } else if (component.types.indexOf("sublocality") >= 0) {
22530 result.district = component.short_name;
22531 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22532 result.stateOrProvince = component.short_name;
22533 } else if (component.types.indexOf("country") >= 0) {
22534 result.country = component.short_name;
22538 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22539 result.addressLine2 = "";
22543 setZoomLevel: function(zoom)
22545 this.gMapContext.map.setZoom(zoom);
22558 this.fireEvent('show', this);
22569 this.fireEvent('hide', this);
22574 Roo.apply(Roo.bootstrap.LocationPicker, {
22576 OverlayView : function(map, options)
22578 options = options || {};
22592 * @class Roo.bootstrap.Alert
22593 * @extends Roo.bootstrap.Component
22594 * Bootstrap Alert class
22595 * @cfg {String} title The title of alert
22596 * @cfg {String} html The content of alert
22597 * @cfg {String} weight ( success | info | warning | danger )
22598 * @cfg {String} faicon font-awesomeicon
22601 * Create a new alert
22602 * @param {Object} config The config object
22606 Roo.bootstrap.Alert = function(config){
22607 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22611 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22618 getAutoCreate : function()
22627 cls : 'roo-alert-icon'
22632 cls : 'roo-alert-title',
22637 cls : 'roo-alert-text',
22644 cfg.cn[0].cls += ' fa ' + this.faicon;
22648 cfg.cls += ' alert-' + this.weight;
22654 initEvents: function()
22656 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22659 setTitle : function(str)
22661 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22664 setText : function(str)
22666 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22669 setWeight : function(weight)
22672 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22675 this.weight = weight;
22677 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22680 setIcon : function(icon)
22683 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22688 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);